Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package librist for openSUSE:Factory checked in at 2025-03-26 21:17:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/librist (Old) and /work/SRC/openSUSE:Factory/.librist.new.2696 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "librist" Wed Mar 26 21:17:50 2025 rev:4 rq:1255845 version:0.2.11 Changes: -------- --- /work/SRC/openSUSE:Factory/librist/librist.changes 2023-11-13 22:16:03.244861870 +0100 +++ /work/SRC/openSUSE:Factory/.librist.new.2696/librist.changes 2025-03-26 21:19:23.056455582 +0100 @@ -1,0 +2,13 @@ +Sat Mar 22 21:46:45 UTC 2025 - Andreas Stieger <andreas.stie...@gmx.de> + +- update to 0.2.11: + * Adds support for ephemeral listening ports, which allows for + adding or taking down ports, primarily for new connections, + after initialization + * Adds a sender function rist_sender_npd_get to obtain current + status of null_packet_deletion in client code + * Adds a new function rist_peer_get_cname to allow for the + extraction of the private cname property of a peer + * various bug fixes and code improvements + +------------------------------------------------------------------- Old: ---- librist-v0.2.10.tar.gz New: ---- librist-v0.2.11.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ librist.spec ++++++ --- /var/tmp/diff_new_pack.kkvVQt/_old 2025-03-26 21:19:23.576477168 +0100 +++ /var/tmp/diff_new_pack.kkvVQt/_new 2025-03-26 21:19:23.576477168 +0100 @@ -2,6 +2,7 @@ # spec file for package librist # # Copyright (c) 2023 SUSE LLC +# Copyright (c) 2025 Andreas Stieger <andreas.stie...@gmx.de> # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -21,7 +22,7 @@ # BRs would expand rings %bcond_with unbundle Name: librist -Version: 0.2.10 +Version: 0.2.11 Release: 0 Summary: Reliable Internet Stream Transport protocol License: BSD-2-Clause @@ -87,9 +88,11 @@ %{_bindir}/rist* %files -n %{libname} +%license COPYING %{_libdir}/*.so.* %files devel +%license COPYING %{_includedir}/* %{_libdir}/*.so %{_libdir}/pkgconfig/*.pc ++++++ librist-v0.2.10.tar.gz -> librist-v0.2.11.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/README.md new/librist-v0.2.11/README.md --- old/librist-v0.2.10/README.md 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/README.md 2024-11-15 21:43:07.000000000 +0100 @@ -1,6 +1,6 @@  -# librist +# libRIST A library that can be used to easily add the RIST protocol to your application. @@ -12,7 +12,7 @@ ## Goal and Features -The goal of this project is to provide a rist library for **most platforms**. +The goal of this project is to provide a RIST library for **most platforms**. It supports all features from the TR-06-1 and most of the features of TR-06-2. @@ -22,7 +22,7 @@ ## License -**librist** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders. +**libRIST** is released under a very liberal license, a contrario from the other VideoLAN projects, so that it can be embedded anywhere, including non-open-source software; or even drivers, to allow the creation of hybrid decoders. The reasoning behind this decision is the same as for libvorbis, see [RMS on vorbis](https://lwn.net/2001/0301/a/rms-ov-license.php3). @@ -97,6 +97,11 @@ 1. Simply do a `docker build` on the Dockerfile in the 'common' subdirectory +# Install with HomeBrew on MacOS + +1. Assuming HomeBrew is already setup, enter "brew install librist" in a terminal. +2. libRIST will be installed in /usr/local, except on Arm64-based Macs, where the root is /opt/homebrew. Make sure to have the bin folder (/usr/local/bin or /opt/homebrew/bin, respectively) in your PATH. + # Support This project is partially funded by SipRadius LLC. @@ -106,11 +111,15 @@ # FAQ -## Why do you not improve srt rather than starting a new project? +## Why do you not improve SRT rather than starting a new project? + +- Although SRT provides a similar solution, it is the result of the vision and design of a single company, Haivision, and it is maintained almost exclusively by Haivision paid developers. RIST on the other hand, was the collective design work of a large group of experts (companies) that have been providing packet recovery services for many years. From its conception, RIST has been based on clear and open standards. Just from SipRadius installations alone, top tier broadcasters have over 4000 RIST point-to-point links running 24/7h. + +Here is a table of comparison of the two protocols: -- Although SRT provides a similar solution, it is the result of the vision and design of a single company. librist on the other hand, was the collective design work of a large group of experts (companies) that have been providing packet recovery services for many years. From its conception, rist has been based on clear and open standards. + -## Is librist an acronym? +## Is libRIST an acronym? - Yes, libRIST stands for Library - Reliable Internet Stream Transport Binary files old/librist-v0.2.10/docs/RIST_vs_SRT.png and new/librist-v0.2.11/docs/RIST_vs_SRT.png differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/include/librist/logging.h new/librist-v0.2.11/include/librist/logging.h --- old/librist-v0.2.10/include/librist/logging.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/include/librist/logging.h 2024-11-15 21:43:07.000000000 +0100 @@ -41,14 +41,25 @@ * when using UDP logging to prevent fd's leaking. **/ +#if !defined(__cplusplus) || __cplusplus >= 202002L #define LOGGING_SETTINGS_INITIALIZER \ - { \ - .log_level = RIST_LOG_DISABLE, \ + { \ + .log_level = RIST_LOG_DISABLE, \ .log_cb = NULL, \ - .log_cb_arg = NULL, \ + .log_cb_arg = NULL, \ .log_socket = -1, \ .log_stream = NULL, \ - } + } +#else +#define LOGGING_SETTINGS_INITIALIZER \ + { \ + RIST_LOG_DISABLE, \ + NULL, \ + NULL, \ + -1, \ + NULL, \ + } +#endif struct rist_logging_settings { enum rist_log_level log_level;///<minimum log level diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/include/librist/peer.h new/librist-v0.2.11/include/librist/peer.h --- old/librist-v0.2.10/include/librist/peer.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/include/librist/peer.h 2024-11-15 21:43:07.000000000 +0100 @@ -115,7 +115,7 @@ /* Connection options */ uint32_t session_timeout; uint32_t keepalive_interval; - uint32_t timing_mode; + enum rist_timing_mode timing_mode; char srp_username[RIST_MAX_STRING_LONG]; char srp_password[RIST_MAX_STRING_LONG]; }; @@ -240,6 +240,15 @@ RIST_API uint32_t rist_peer_get_id(const struct rist_peer *peer); +/** + * @brief Retrieve the cname associated to a peer (if any) + * + * @param peer The peer to extract the cname from + * @param[out] cname a pointer to the string containing the cname + * @return the length of the cname string + */ +RIST_API uint32_t rist_peer_get_cname(const struct rist_peer *peer, const char **cname); + #if HAVE_SRP_SUPPORT /* @brief Update the shared passphrase for the peer diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/include/librist/sender.h new/librist-v0.2.11/include/librist/sender.h --- old/librist-v0.2.10/include/librist/sender.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/include/librist/sender.h 2024-11-15 21:43:07.000000000 +0100 @@ -6,6 +6,7 @@ #include "headers.h" #include <stdint.h> +#include <stdbool.h> #ifdef __cplusplus extern "C" { @@ -36,6 +37,17 @@ uint32_t flow_id, struct rist_logging_settings *logging_settings); /** + * @brief Get RIST NULL Packet deletion status + * + * Returns the current status of NULL Packet deletion (NPD). + * + * @param ctx RIST sender ctx + * @param[out] npd current NPD status, true if NPD is enabled. + * @return 0 on success, -1 in case of error. + */ +RIST_API int rist_sender_npd_get(const struct rist_ctx *ctx, bool *npd); + +/** * @brief Enable RIST NULL Packet deletion * * Enables deletion of NULL packets, packets are modified on submission to diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/include/meson.build new/librist-v0.2.11/include/meson.build --- old/librist-v0.2.10/include/meson.build 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/include/meson.build 2024-11-15 21:43:07.000000000 +0100 @@ -5,7 +5,7 @@ librist_git_dir = join_paths(librist_src_root, '.git') rev_target = vcs_tag(command: [ 'git', '--git-dir', librist_git_dir, - '--work-tree', meson.source_root(), + '--work-tree', librist_src_root, 'describe', '--tags', '--dirty', '--match', 'v?.*', '--always' ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/meson.build new/librist-v0.2.11/meson.build --- old/librist-v0.2.10/meson.build 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/meson.build 2024-11-15 21:43:07.000000000 +0100 @@ -4,7 +4,7 @@ # SPDX-License-Identifier: BSD-2-Clause project('libRIST', 'c', - version: '0.2.10', + version: '0.2.11', default_options: ['c_std=c99', 'warning_level=3', 'libdir=lib'], meson_version: '>= 0.51.0') @@ -17,9 +17,9 @@ #If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0. #If any interfaces have been added since the last public release, then increment age. #If any interfaces have been removed or changed since the last public release, then set age to 0. -librist_abi_current = 7 -librist_abi_revision = 1 -librist_abi_age = 3 +librist_abi_current = 8 +librist_abi_revision = 0 +librist_abi_age = 4 librist_soversion = librist_abi_current - librist_abi_age librist_version = '@0@.@1@.@2@'.format(librist_abi_current - librist_abi_age, librist_abi_age, librist_abi_revision) @@ -30,7 +30,7 @@ #PATCH not used (doesn't make sense for API version, remains here for backwards compat) librist_api_version_major = 4 -librist_api_version_minor = 4 +librist_api_version_minor = 5 librist_api_version_patch = 0 librist_src_root = meson.current_source_dir() @@ -39,6 +39,11 @@ platform_files = [] inc = [] inc += include_directories('.', 'src', 'include/librist', 'include', 'contrib') +if (host_machine.system() == 'darwin') + r = run_command('brew', '--prefix', check: true) + brewoutput = r.stdout().strip() + inc += include_directories(brewoutput + '/include') +endif #builtin_lz4 = get_option('builtin_lz4') builtin_cjson = get_option('builtin_cjson') @@ -375,10 +380,10 @@ run_target('cppcheck', command : ['cppcheck', '--quiet', '--std=c99', - '--suppressions-list=' + join_paths(meson.source_root(), 'common/configs/cppcheck-suppressions.txt'), + '--suppressions-list=' + join_paths(librist_src_root, 'common/configs/cppcheck-suppressions.txt'), '--project=' + join_paths(meson.build_root(), 'compile_commands.json')]) - run_target('analyze', command: ['bash', join_paths(meson.source_root(), 'common/scripts/analyze.sh')]) + run_target('analyze', command: ['bash', join_paths(librist_src_root, 'common/scripts/analyze.sh')]) endif librist_dep = declare_dependency(include_directories: inc, link_with : librist) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/crypto/srp.c new/librist-v0.2.11/src/crypto/srp.c --- old/librist-v0.2.10/src/crypto/srp.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/crypto/srp.c 2024-11-15 21:43:07.000000000 +0100 @@ -799,7 +799,7 @@ if (!s_bytes || s_len == 0 || (!default_ng && (!N_bytes || N_len == 0 || !g_bytes || g_len == 0))) return NULL; - struct librist_crypto_srp_client_ctx *ctx = calloc(sizeof(*ctx), 1); + struct librist_crypto_srp_client_ctx *ctx = calloc(1, sizeof(*ctx)); if (!ctx) return NULL; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/flow.c new/librist-v0.2.11/src/flow.c --- old/librist-v0.2.10/src/flow.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/flow.c 2024-11-15 21:43:07.000000000 +0100 @@ -300,6 +300,11 @@ f->flow_auto_buffer_scaling = true; } + if (p->session_timeout > f->session_timeout) { + f->session_timeout = p->session_timeout; + rist_log_priv(&ctx->common, RIST_LOG_INFO, "Setting flow session timeout to %"PRIu64"ms\n", f->session_timeout / RIST_CLOCK); + } + // Set the flow timeout as the buffer size for the flow // However, we start with 250 ms as the minimum/default // to make sure it is larger than the RTCP interval diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/libevsocket.c new/librist-v0.2.11/src/libevsocket.c --- old/librist-v0.2.10/src/libevsocket.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/libevsocket.c 2024-11-15 21:43:07.000000000 +0100 @@ -182,7 +182,7 @@ if (ctx->n_events > 0) { ctx->pfd = malloc(sizeof(struct pollfd) * ctx->n_events); - ctx->_array = calloc(sizeof(struct evsocket_event), ctx->n_events); + ctx->_array = calloc(ctx->n_events, sizeof(struct evsocket_event)); } if ((!ctx->pfd) || (!ctx->_array)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/mpegts.c new/librist-v0.2.11/src/mpegts.c --- old/librist-v0.2.10/src/mpegts.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/mpegts.c 2024-11-15 21:43:07.000000000 +0100 @@ -23,56 +23,70 @@ return -1; SET_BIT(header_ext->flags, 7); size_t offset = 0; - size_t output_offset = 0; - //size_t bytes_remaining = *payload_len - packet_size; - struct mpegts_header *hdr = (struct mpegts_header *)&payload_in[offset]; int suppressed = 0; - if (RIST_UNLIKELY(hdr->syncbyte != 0x47)) + struct mpegts_header *hdr = (struct mpegts_header *)&payload_in[offset]; + if (RIST_UNLIKELY(hdr->syncbyte != 0x47)) goto fail; - for (int i = (int)count -1; i >= 0; i--) { + + for (int i = 0; i <= (int)count-1; i++) { if (be16toh(hdr->flags1) == 0x1FFF) { *payload_len -= packet_size; - SET_BIT(header_ext->npd_bits, i); + SET_BIT(header_ext->npd_bits, (6 - i)); suppressed++; - } else { - if (i == 0 && suppressed == 0) - return 0; + } + offset += packet_size; + hdr = (struct mpegts_header *)&payload_in[offset]; + } + + if (suppressed == 0) + return 0; + + offset = 0; + size_t output_offset = 0; + for (int i = 0; i <= (int)count-1; i++) { + if (CHECK_BIT(header_ext->npd_bits, (6 - i)) == 0) { memcpy(&payload_out[output_offset], &payload_in[offset], packet_size); output_offset += packet_size; } offset += packet_size; - //bytes_remaining -= packet_size; - hdr = (struct mpegts_header *)&payload_in[offset]; } + return suppressed; fail: UNSET_BIT(header_ext->flags, 7); return -1; } -int expand_null_packets(uint8_t payload[], size_t *payload_len, uint8_t npd_bits) { +int expand_null_packets(uint8_t payload_in[], uint8_t payload_out[], size_t *payload_len, uint8_t npd_bits) { size_t packet_size = CHECK_BIT(npd_bits, 7) == 0? 188: 204; + + // Non-null date + int ts_count = *payload_len / packet_size; + // Null packets defined in header + int null_count = CHECK_BIT(npd_bits, 6) + CHECK_BIT(npd_bits, 5) + CHECK_BIT(npd_bits, 4) + CHECK_BIT(npd_bits, 3) + CHECK_BIT(npd_bits, 2) + CHECK_BIT(npd_bits, 1) + CHECK_BIT(npd_bits, 0); + + if (null_count == 0) + return 0; + size_t offset = 0; - ssize_t remaining_bytes = *payload_len; - //We will be modifying the payload in a 10k byte pre-allocated buffer, so we should be able to get away without any memory management - int counter = 0; - for (int i = 6; i >= 0; i--) - { - if (CHECK_BIT(npd_bits, i)) - { - if (remaining_bytes > 0) - memmove(&payload[offset + packet_size], &payload[offset], remaining_bytes); - struct mpegts_header * hdr = (struct mpegts_header *)&payload[offset]; + ts_count += null_count; + *payload_len = ts_count * packet_size; + size_t input_offset = 0; + for (int i = 0; i <= (int)ts_count-1; i++) { + if (CHECK_BIT(npd_bits, (6 - i)) == 0) { + memcpy(&payload_out[offset], &payload_in[input_offset], packet_size); + input_offset += packet_size; + } + else { + struct mpegts_header * hdr = (struct mpegts_header *)&payload_out[offset]; memset(hdr, 0, sizeof(*hdr)); hdr->syncbyte = 0x47; hdr->flags1 = htobe16(0x1FFF); SET_BIT(hdr->flags2,4); - memset(&payload[offset + sizeof(*hdr)], 0xff, (packet_size - sizeof(*hdr))); - *payload_len += packet_size; - counter++; - } else - remaining_bytes -= packet_size;//Use this packet, so decrease remaining bytes to move + memset(&payload_out[offset + sizeof(*hdr)], 0xff, (packet_size - sizeof(*hdr))); + } offset += packet_size; } - return counter; + + return *payload_len; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/mpegts.h new/librist-v0.2.11/src/mpegts.h --- old/librist-v0.2.10/src/mpegts.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/mpegts.h 2024-11-15 21:43:07.000000000 +0100 @@ -36,6 +36,6 @@ }) RIST_PRIV int suppress_null_packets(const uint8_t payload_in[], uint8_t payload_out[], size_t *payload_len, struct rist_rtp_hdr_ext *header_ext); -RIST_PRIV int expand_null_packets(uint8_t payload[], size_t *payload_len, uint8_t npd_bits); +RIST_PRIV int expand_null_packets(uint8_t payload_in[], uint8_t payload_out[], size_t *payload_len, uint8_t npd_bits); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/proto/eap.c new/librist-v0.2.11/src/proto/eap.c --- old/librist-v0.2.10/src/proto/eap.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/proto/eap.c 2024-11-15 21:43:07.000000000 +0100 @@ -697,7 +697,7 @@ return 0; if (peer->eap_ctx != NULL) return -1; - struct eapsrp_ctx *ctx = calloc(sizeof(*ctx), 1); + struct eapsrp_ctx *ctx = calloc(1, sizeof(*ctx)); if (!ctx) return -1; @@ -923,7 +923,7 @@ return RIST_ERR_INVALID_PROFILE; if ((peer->listening && !peer->multicast_receiver) || peer->multicast_sender) { - struct eapsrp_ctx *ctx = calloc(sizeof(*ctx), 1); + struct eapsrp_ctx *ctx = calloc(1, sizeof(*ctx)); ctx->config.logging_settings = get_cctx(peer)->logging_settings; if (ctx == NULL) return RIST_ERR_MALLOC; @@ -942,11 +942,15 @@ lookup_func = internal_user_verifier_lookup; const char *n = NULL; const char *g = NULL; - assert(librist_get_ng_constants(LIBRIST_SRP_NG_2048, &n, &g) ==0); + int ret; + ret = librist_get_ng_constants(LIBRIST_SRP_NG_2048, &n, &g); + assert(ret == 0); #if HAVE_MBEDTLS - assert(librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt_old, &ctx->authenticator_len_salt_old, &ctx->authenticator_bytes_verifier_old, &ctx->authenticator_len_verifier_old, false) ==0); + ret = librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt_old, &ctx->authenticator_len_salt_old, &ctx->authenticator_bytes_verifier_old, &ctx->authenticator_len_verifier_old, false); + assert(ret == 0); #endif - assert(librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt, &ctx->authenticator_len_salt, &ctx->authenticator_bytes_verifier, &ctx->authenticator_len_verifier, true) ==0); + ret = librist_crypto_srp_create_verifier(n, g, username, password, &ctx->authenticator_bytes_salt, &ctx->authenticator_len_salt, &ctx->authenticator_bytes_verifier, &ctx->authenticator_len_verifier, true); + assert(ret == 0); strcpy(ctx->authenticator_username, username); userdata = (void *)ctx; rist_log_priv2(ctx->config.logging_settings, RIST_LOG_INFO, EAP_LOG_PREFIX"EAP Authentication enabled, role = authenticator, single user\n"); @@ -960,6 +964,7 @@ ctx->config.lookup_func = lookup_func; ctx->config.lookup_func_userdata = userdata; ctx->config.role = EAP_ROLE_AUTHENTICATOR; + ctx->config.use_key_as_passphrase = peer->key_tx.password_len == 0; ctx->eapversion3 = true; peer->eap_ctx = ctx; struct rist_peer *child = peer->child; @@ -978,7 +983,7 @@ size_t p_len = strlen(password); if (u_len == 0 || u_len > 255 || p_len == 0 || p_len > 255) return RIST_ERR_INVALID_STRING_LENGTH; - struct eapsrp_ctx *ctx = calloc(sizeof(*ctx), 1); + struct eapsrp_ctx *ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) return RIST_ERR_MALLOC; if (pthread_mutex_init(&ctx->eap_lock, NULL) != 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/proto/gre.c new/librist-v0.2.11/src/proto/gre.c --- old/librist-v0.2.10/src/proto/gre.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/proto/gre.c 2024-11-15 21:43:07.000000000 +0100 @@ -205,20 +205,21 @@ return -1; } struct rist_gre_keepalive *ka = (struct rist_gre_keepalive *)buf; - memcpy(info->ka.mac, ka->mac_array, sizeof(ka->mac_array)); - info->ka.x = CHECK_BIT(ka->capabilities1, 7); - info->ka.r = CHECK_BIT(ka->capabilities1, 6); - info->ka.b = CHECK_BIT(ka->capabilities1, 5); - info->ka.a = CHECK_BIT(ka->capabilities1, 4); - info->ka.p = CHECK_BIT(ka->capabilities1, 3); - info->ka.e = CHECK_BIT(ka->capabilities1, 2); - info->ka.l = CHECK_BIT(ka->capabilities1, 1); - info->ka.n = CHECK_BIT(ka->capabilities1, 0); - info->ka.d = CHECK_BIT(ka->capabilities2, 7); - info->ka.t = CHECK_BIT(ka->capabilities2, 6); - info->ka.v = CHECK_BIT(ka->capabilities2, 5); - info->ka.j = CHECK_BIT(ka->capabilities2, 4); - info->ka.f = CHECK_BIT(ka->capabilities2, 3); + memcpy(&info->ka, ka, SIZEOF_GRE_KEEPALIVE); + memcpy(info->mac, ka->mac_array, sizeof(ka->mac_array)); + info->x = CHECK_BIT(ka->capabilities1, 7); + info->r = CHECK_BIT(ka->capabilities1, 6); + info->b = CHECK_BIT(ka->capabilities1, 5); + info->a = CHECK_BIT(ka->capabilities1, 4); + info->p = CHECK_BIT(ka->capabilities1, 3); + info->e = CHECK_BIT(ka->capabilities1, 2); + info->l = CHECK_BIT(ka->capabilities1, 1); + info->n = CHECK_BIT(ka->capabilities1, 0); + info->d = CHECK_BIT(ka->capabilities2, 7); + info->t = CHECK_BIT(ka->capabilities2, 6); + info->v = CHECK_BIT(ka->capabilities2, 5); + info->j = CHECK_BIT(ka->capabilities2, 4); + info->f = CHECK_BIT(ka->capabilities2, 3); info->json_len = buflen - sizeof(*ka); if (info->json_len > 0) { info->json = (const char *)&buf[sizeof(*ka)]; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/proto/gre.h new/librist-v0.2.11/src/proto/gre.h --- old/librist-v0.2.10/src/proto/gre.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/proto/gre.h 2024-11-15 21:43:07.000000000 +0100 @@ -120,6 +120,8 @@ */ +#define SIZEOF_GRE_KEEPALIVE 8 + RIST_PACKED_STRUCT(rist_gre_keepalive,{ uint8_t mac_array[6]; uint8_t capabilities1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/proto/protocol_gre.h new/librist-v0.2.11/src/proto/protocol_gre.h --- old/librist-v0.2.10/src/proto/protocol_gre.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/proto/protocol_gre.h 2024-11-15 21:43:07.000000000 +0100 @@ -5,9 +5,24 @@ #include <stdint.h> #include <stddef.h> #include "rist-private.h" +#include "proto/gre.h" struct rist_keepalive_info { - struct rist_keepalive_data ka; + uint8_t ka[SIZEOF_GRE_KEEPALIVE]; + uint8_t mac[6]; + bool x : 1; + bool r : 1; + bool b : 1; + bool a : 1; + bool p : 1; + bool e : 1; + bool l : 1; + bool n : 1; + bool d : 1; + bool t : 1; + bool v : 1; + bool j : 1; + bool f : 1; size_t json_len; const char *json; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/proto/rtp.h new/librist-v0.2.11/src/proto/rtp.h --- old/librist-v0.2.10/src/proto/rtp.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/proto/rtp.h 2024-11-15 21:43:07.000000000 +0100 @@ -82,12 +82,20 @@ // RTCP constants #define RTCP_FB_HEADER_SIZE 12 +#define PTYPE_RTCP_CUSTOM1 72 +#define PTYPE_RTCP_CUSTOM2 73 +#define PTYPE_RTCP_CUSTOM3 74 +#define PTYPE_RTCP_CUSTOM4 75 +#define PTYPE_RTCP_CUSTOM5 76 +#define PTYPE_XR 77 + #define PTYPE_SR 200 #define PTYPE_RR 201 #define PTYPE_SDES 202 -#define PTYPE_XR 207 #define PTYPE_NACK_CUSTOM 204 #define PTYPE_NACK_BITMASK 205 +// To be deprecated in the future +#define PTYPE_XR_LEGACY 207 #define NACK_FMT_BITMASK 1 #define NACK_FMT_RANGE 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/rist-common.c new/librist-v0.2.11/src/rist-common.c --- old/librist-v0.2.10/src/rist-common.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/rist-common.c 2024-11-15 21:43:07.000000000 +0100 @@ -31,7 +31,7 @@ #include <stdbool.h> #include "stdio-shim.h" #include <assert.h> - +#include "proto/gre.h" static void rist_peer_recv(struct evsocket_ctx *evctx, int fd, short revents, void *arg, bool *again); static void rist_peer_recv_wrap(struct evsocket_ctx *evctx, int fd, short revents, void *arg); @@ -978,6 +978,8 @@ atomic_store_explicit(&f->fifo_overflow, true, memory_order_release); } else { + if (RIST_UNLIKELY(f->fifo_overflow == true)) + atomic_store_explicit(&f->fifo_overflow, false, memory_order_release); f->dataout_fifo_queue[dataout_fifo_write_index] = block; atomic_store_explicit(&f->dataout_fifo_queue_write_index, (dataout_fifo_write_index + 1)& (ctx->fifo_queue_size-1), memory_order_relaxed); // Wake up the fifo read thread (poll) @@ -2357,6 +2359,7 @@ struct sockaddr *addr = (struct sockaddr *)&ss; struct rist_peer *p = NULL; uint8_t *recv_buf = cctx->buf.recv; + uint8_t *recv_buf_npd = cctx->buf.recv_npd; uint16_t port = 0; ssize_t ret = recvfrom(peer->sd, (char*)recv_buf, RIST_MAX_PACKET_SIZE, MSG_DONTWAIT, (struct sockaddr *)addr, &addrlen); @@ -2708,12 +2711,12 @@ "New keepalive received. MAC: %x:%x:%x:%x:%x:%x" " X: %d R: %d B: %d A: %d P: %d E: %d L: %d: N: %d" " D: %d T: %d V: %d: J: %d F: %d\n", - info.ka.mac[0], info.ka.mac[1], info.ka.mac[2], - info.ka.mac[3], info.ka.mac[4], info.ka.mac[5], - info.ka.x, info.ka.r, info.ka.b, info.ka.a, - info.ka.p, info.ka.e, info.ka.l, info.ka.e, - info.ka.n, info.ka.d, info.ka.t, info.ka.v, - info.ka.j, info.ka.f); + info.mac[0], info.mac[1], info.mac[2], + info.mac[3], info.mac[4], info.mac[5], + info.x, info.r, info.b, info.a, + info.p, info.e, info.l, info.e, + info.n, info.d, info.t, info.v, + info.j, info.f); if (info.json_len) rist_log_priv(get_cctx(peer), RIST_LOG_INFO, "Keepalive JSON:\n%.*s\n", info.json_len, info.json); //TODO: add callback? @@ -2740,11 +2743,24 @@ return; } + // This is for legacy compatibility (to be removed later) + if (rtp->payload_type == PTYPE_XR_LEGACY) + rtp->payload_type = PTYPE_XR; + uint32_t rtp_time = 0; uint64_t source_time = 0; + uint8_t payload_type = rtp->payload_type; + uint8_t payload_type_nomarker_bit = rtp->payload_type & 127; + if (cctx->profile == RIST_PROFILE_SIMPLE || gre_proto == RIST_GRE_PROTOCOL_TYPE_REDUCED) { // Finish defining the payload (we assume reduced header) - if(rtp->payload_type < 200) { + // The check is for 200-205 and 72-77 (payload type minus 128) + if(payload_type_nomarker_bit < 72 || payload_type_nomarker_bit > 77) { + // This will mis-clasify rtp packets with payload types 72-77 as rtcp. However, + // this range is reserved for "RTCP conflict avoidanceâ on RFC4855. Furthermore, + // we are already using 77 for PTYPE_XR + // Remove the marker bit as it is not part of the payload type for non-rtcp data + payload_type = payload_type_nomarker_bit; flow_id = be32toh(rtp->ssrc); // If this is a retry, extract the information and restore correct flow_id if (flow_id & 1UL) @@ -2758,16 +2774,20 @@ payload.data = (void *)data_payload; if (CHECK_BIT(rtp->flags, 4)) { + uint8_t *data_payload_out = &recv_buf_npd[0]; //RTP extension header struct rist_rtp_hdr_ext * hdr_ext = (struct rist_rtp_hdr_ext *)(&recv_buf[payload_offset]); + payload.size -= sizeof(*hdr_ext); + data_payload += sizeof(*hdr_ext); + payload.data = (void *)data_payload; if (memcmp(&hdr_ext->identifier, "RI", 2) == 0 && be16toh(hdr_ext->length) == 1) { - payload.size -= sizeof(*hdr_ext); - data_payload += sizeof(*hdr_ext); - if (CHECK_BIT(hdr_ext->flags, 7)) - expand_null_packets(data_payload, &payload.size, hdr_ext->npd_bits); + // Null packet expansion (use a separate buffer and replace it when we had nulls) + if (CHECK_BIT(hdr_ext->flags, 7)) { + if (expand_null_packets(data_payload, data_payload_out, &payload.size, hdr_ext->npd_bits)) + payload.data = (void *)data_payload_out; + } } - payload.data = (void *)data_payload; } payload.type = RIST_PAYLOAD_TYPE_DATA_RAW; } else { @@ -2862,14 +2882,14 @@ if (RIST_UNLIKELY(p->config.timing_mode == RIST_TIMING_MODE_ARRIVAL)) source_time = timestampNTP_u64(); else - source_time = convertRTPtoNTP(rtp->payload_type, time_extension, rtp_time); + source_time = convertRTPtoNTP(payload_type, time_extension, rtp_time); seq = (uint32_t)be16toh(rtp->seq); if (RIST_UNLIKELY(!p->receiver_mode)) rist_log_priv(get_cctx(peer), RIST_LOG_WARN, "Received data packet on sender, ignoring (%d bytes)...\n", payload.size); else { rist_calculate_bitrate((recv_bufsize - payload_offset), &p->bw);//use the unexpanded size to show real BW - rist_receiver_recv_data(p, seq, flow_id, source_time, now, &payload, retry, rtp->payload_type); + rist_receiver_recv_data(p, seq, flow_id, source_time, now, &payload, retry, payload_type); } break; case RIST_PAYLOAD_TYPE_EAPOL: @@ -3187,7 +3207,6 @@ diff = tmp_target_buffer_size - target_recovery_buffer_size; if (diff > RIST_CLOCK * 15) { - rist_log_priv(&receiver_ctx->common, RIST_LOG_INFO, "Adjusting flow buffer time to %"PRIu64"ms\n", tmp_target_buffer_size/ RIST_CLOCK); target_recovery_buffer_size = tmp_target_buffer_size; buffer_adjust_step_size = diff / 100; buffer_adjust_steps_left = 100; @@ -3198,6 +3217,8 @@ if ((target_recovery_buffer_size *2ULL) > flow->session_timeout) flow->session_timeout = 2ULL * target_recovery_buffer_size; flow->currently_scaling_buffer = true; + rist_log_priv(&receiver_ctx->common, RIST_LOG_INFO, "Adjusting flow buffer time to %"PRIu64"ms, flow timeout is %"PRIu64"ms\n", tmp_target_buffer_size/ RIST_CLOCK, flow->session_timeout/ RIST_CLOCK); + } } } else if (now >= next_buffer_adjust_step) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/rist-private.h new/librist-v0.2.11/src/rist-private.h --- old/librist-v0.2.10/src/rist-private.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/rist-private.h 2024-11-15 21:43:07.000000000 +0100 @@ -30,6 +30,7 @@ #include <errno.h> #include <stdatomic.h> #include "librist/logging.h" +#include "proto/gre.h" #undef RIST_DEPRECATED @@ -300,6 +301,7 @@ uint8_t enc[RIST_MAX_PACKET_SIZE]; uint8_t dec[RIST_MAX_PACKET_SIZE]; uint8_t recv[RIST_MAX_PACKET_SIZE]; + uint8_t recv_npd[RIST_MAX_PACKET_SIZE]; uint8_t rtcp[RIST_MAX_PACKET_SIZE]; } buf; struct rist_buffer *rist_free_buffer; @@ -453,23 +455,6 @@ struct rist_receiver *receiver_ctx; }; -struct rist_keepalive_data { - uint8_t mac[6]; - bool x : 1; - bool r : 1; - bool b : 1; - bool a : 1; - bool p : 1; - bool e : 1; - bool l : 1; - bool n : 1; - bool d : 1; - bool t : 1; - bool v : 1; - bool j : 1; - bool f : 1; -}; - struct rist_peer { /* linked list */ pthread_mutex_t peer_lock;//Currently only used for setting password & in sending/receiving @@ -615,7 +600,8 @@ uint64_t log_repeat_timer; - struct rist_keepalive_data data; + uint8_t data[SIZEOF_GRE_KEEPALIVE]; + }; static inline struct rist_common_ctx *rist_struct_get_common(struct rist_ctx *ctx) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/rist.c new/librist-v0.2.11/src/rist.c --- old/librist-v0.2.10/src/rist.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/rist.c 2024-11-15 21:43:07.000000000 +0100 @@ -203,11 +203,7 @@ *data_buffer = data_block; - bool overflow = false; - while (!atomic_compare_exchange_weak(&f->fifo_overflow, &overflow, false)) { - // - } - if (overflow) + if (RIST_UNLIKELY(f->fifo_overflow == true)) data_block->flags |= RIST_DATA_FLAGS_OVERFLOW; return (int)num; @@ -441,16 +437,33 @@ return 0; } +int rist_sender_npd_get(const struct rist_ctx *rist_ctx, bool *npd) +{ + if (RIST_UNLIKELY(!rist_ctx)) + { + rist_log_priv3(RIST_LOG_ERROR, "rist_sender_npd_get call with null context"); + return -1; + } + if (RIST_UNLIKELY(rist_ctx->mode != RIST_SENDER_MODE || !rist_ctx->sender_ctx)) + { + rist_log_priv3(RIST_LOG_ERROR, "rist_sender_npd_get call with ctx not set up for sending\n"); + return -1; + } + const struct rist_sender *ctx = rist_ctx->sender_ctx; + *npd = ctx->null_packet_suppression; + return 0; +} + int rist_sender_npd_enable(struct rist_ctx *rist_ctx) { if (RIST_UNLIKELY(!rist_ctx)) { - rist_log_priv3(RIST_LOG_ERROR, "rist_sender_flow_id_set call with null context"); + rist_log_priv3(RIST_LOG_ERROR, "rist_sender_npd_enable call with null context"); return -1; } if (RIST_UNLIKELY(rist_ctx->mode != RIST_SENDER_MODE || !rist_ctx->sender_ctx)) { - rist_log_priv3(RIST_LOG_ERROR, "rist_sender_flow_id_set call with ctx not set up for sending\n"); + rist_log_priv3(RIST_LOG_ERROR, "rist_sender_npd_enable call with ctx not set up for sending\n"); return -1; } struct rist_sender *ctx = rist_ctx->sender_ctx; @@ -463,12 +476,12 @@ { if (RIST_UNLIKELY(!rist_ctx)) { - rist_log_priv3(RIST_LOG_ERROR, "rist_sender_flow_id_set call with null context"); + rist_log_priv3(RIST_LOG_ERROR, "rist_sender_npd_disable call with null context"); return -1; } if (RIST_UNLIKELY(rist_ctx->mode != RIST_SENDER_MODE || !rist_ctx->sender_ctx)) { - rist_log_priv3(RIST_LOG_ERROR, "rist_sender_flow_id_set call with ctx not set up for sending\n"); + rist_log_priv3(RIST_LOG_ERROR, "rist_sender_npd_disable call with ctx not set up for sending\n"); return -1; } struct rist_sender *ctx = rist_ctx->sender_ctx; @@ -662,6 +675,17 @@ return peer->adv_peer_id; } +uint32_t rist_peer_get_cname(const struct rist_peer *peer, const char **cname) +{ + if (peer) + { + *cname = &peer->cname[0]; + return strlen(*cname); + } + else + return 0; +} + int rist_peer_config_free(const struct rist_peer_config **peer_config) { return rist_peer_config_free2((struct rist_peer_config **)peer_config); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/udp.c new/librist-v0.2.11/src/udp.c --- old/librist-v0.2.10/src/udp.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/udp.c 2024-11-15 21:43:07.000000000 +0100 @@ -329,7 +329,7 @@ return; } - if (peer->local_port) { + if (peer->listening) { const char* host; uint16_t port; @@ -361,6 +361,26 @@ peer->sd = udpsocket_open_bind(host, port, peer->miface); if (peer->sd >= 0) { + if (port == 0) + { + // Populate peer->local_port with ephemeral port assigned + struct sockaddr_storage local_addr; + socklen_t n = sizeof( struct sockaddr_storage ); + if( getsockname( peer->sd, (struct sockaddr *) &local_addr, &n ) != 0) + rist_log_priv(get_cctx(peer), RIST_LOG_INFO, "Could not find assigned port (socket# %d)\n", peer->sd); + else + { + if (local_addr.ss_family == AF_INET) { + struct sockaddr_in *a = (struct sockaddr_in *)&local_addr; + port = a->sin_port; + } else { + /* ipv6 */ + struct sockaddr_in6 *a = (struct sockaddr_in6 *)&local_addr; + port = a->sin6_port; + } + peer->local_port = port; + } + } rist_log_priv(get_cctx(peer), RIST_LOG_INFO, "Starting in URL listening mode (socket# %d)\n", peer->sd); } else { rist_log_priv(get_cctx(peer), RIST_LOG_ERROR, "Could not start in URL listening mode. %s\n", strerror(errno)); @@ -435,6 +455,9 @@ #endif } peer->local_port = 32768 + (get_cctx(peer)->peer_counter % 28232); +#ifdef _WIN32 + udpsocket_set_nonblocking(peer->sd); +#endif } // Increase default OS udp receive buffer size diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/src/udpsocket.c new/librist-v0.2.11/src/udpsocket.c --- old/librist-v0.2.10/src/udpsocket.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/src/udpsocket.c 2024-11-15 21:43:07.000000000 +0100 @@ -312,23 +312,15 @@ /* Non-critical error */ rist_log_priv3( RIST_LOG_ERROR, "Cannot set SO_REUSEADDR: %s\n", strerror(errno)); } - - if (is_multicast) { - struct sockaddr_in6 sa = { .sin6_family = raw.sin6_family, .sin6_port = raw.sin6_port }; - if (bind(sd, (struct sockaddr *)&sa, addrlen) < 0) { - rist_log_priv3(RIST_LOG_ERROR, "Could not bind to interface: %s\n", strerror(errno)); - udpsocket_close(sd); - return -1; - } - if (udpsocket_join_mcast_group(sd, mciface, (struct sockaddr *)&raw, raw.sin6_family) != 0) { - rist_log_priv3( RIST_LOG_ERROR, "Could not join multicast group: %s on %s\n", host, mciface); - return -1; - } - } else if (bind(sd, (struct sockaddr *)&raw, addrlen) < 0) { + if (bind(sd, (struct sockaddr *)&raw, addrlen) < 0) { rist_log_priv3( RIST_LOG_ERROR, "Could not bind to interface: %s\n", strerror(errno)); udpsocket_close(sd); return -1; } + if (is_multicast && udpsocket_join_mcast_group(sd, mciface, (struct sockaddr *)&raw, raw.sin6_family) != 0) { + rist_log_priv3( RIST_LOG_ERROR, "Could not join multicast group: %s on %s\n", host, mciface); + return -1; + } return sd; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/test/rist/meson.build new/librist-v0.2.11/test/rist/meson.build --- old/librist-v0.2.10/test/rist/meson.build 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/test/rist/meson.build 2024-11-15 21:43:07.000000000 +0100 @@ -17,6 +17,7 @@ link_with: librist, dependencies: [ threads, + tools_dependencies, stdatomic_dependency ]) @@ -26,12 +27,17 @@ test('Simple profile unicast', test_send_receive, args: ['0', 'rist://@127.0.0.1:1234', 'rist://127.0.0.1:1234', '0'], suite: ['simple', 'unicast']) test('Simple profile unicast packet loss 10%', test_send_receive, args: ['0', 'rist://@127.0.0.1:2234', 'rist://127.0.0.1:2234', '10'],suite: ['simple', 'unicast']) test('Simple profile unicast packet loss 25%', test_send_receive, args: ['0', 'rist://@127.0.0.1:3234', 'rist://127.0.0.1:3234', '25'],suite: ['simple', 'unicast']) -#Multicast -test('Simple profile multicast', test_send_receive, args: ['0', 'rist://@239.0.0.1:1234?rtt-max=10&rtt-min=1', 'rist://239.0.0.1:1234?rtt-max=10&rtt-min=1', '0'],suite: ['simple', 'multicast']) -test('Simple profile multicast packet loss 10%', test_send_receive, args: ['0', 'rist://@239.0.0.2:2234?rtt-max=10&rtt-min=1', 'rist://239.0.0.2:2234?rtt-max=10&rtt-min=1', '10'],suite: ['simple', 'multicast']) -test('Simple profile multicast packet loss 25%', test_send_receive, args: ['0', 'rist://@239.0.0.3:3234?rtt-max=10&rtt-min=1', 'rist://239.0.0.3:3234?rtt-max=10&rtt-min=1', '25'],suite: ['simple', 'multicast']) +if (host_machine.system() != 'darwin') + #Multicast + test('Simple profile multicast', test_send_receive, args: ['0', 'rist://@239.0.0.1:1236?rtt-max=10&rtt-min=1', 'rist://239.0.0.1:1236?rtt-max=10&rtt-min=1', '0'],suite: ['simple', 'multicast']) + test('Simple profile multicast packet loss 10%', test_send_receive, args: ['0', 'rist://@239.0.0.2:2236?rtt-max=10&rtt-min=1', 'rist://239.0.0.2:2236?rtt-max=10&rtt-min=1', '10'],suite: ['simple', 'multicast']) + test('Simple profile multicast packet loss 25%', test_send_receive, args: ['0', 'rist://@239.0.0.3:3236?rtt-max=10&rtt-min=1', 'rist://239.0.0.3:3236?rtt-max=10&rtt-min=1', '25'],suite: ['simple', 'multicast']) +endif ###Main profile tests: +#Null Packet Deletion +test('Main profile NPD receive server mode, sender client mode', test_send_receive, args: ['1', 'rist://@127.0.0.1:3501?rtt-max=10&rtt-min=1', 'rist://127.0.0.1:3501?rtt-max=10&rtt-min=1', '0', '1'], suite: ['main', 'unicast', 'server', 'NPD']) +test('Main profile NPD receive client mode, sender server mode', test_send_receive, args: ['1', 'rist://127.0.0.1:3502?rtt-max=10&rtt-min=1', 'rist://@127.0.0.1:3502?rtt-max=10&rtt-min=1', '0', '1'], suite: ['main', 'unicast', 'client', 'NPD']) #Sender connecting to receiver test('Main profile receive server mode, sender client mode', test_send_receive, args: ['1', 'rist://@127.0.0.1:4001?rtt-max=10&rtt-min=1', 'rist://127.0.0.1:4001?rtt-max=10&rtt-min=1', '0'],suite: ['main', 'unicast', 'server']) test('Main profile receive server mode, sender client mode packet loss 10%', test_send_receive, args: ['1', 'rist://@127.0.0.1:4002?rtt-max=10&rtt-min=1', 'rist://127.0.0.1:4002?rtt-max=10&rtt-min=1', '10'],suite: ['main', 'unicast', 'server']) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/test/rist/test_send_receive.c new/librist-v0.2.11/test/rist/test_send_receive.c --- old/librist-v0.2.10/test/rist/test_send_receive.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/test/rist/test_send_receive.c 2024-11-15 21:43:07.000000000 +0100 @@ -1,4 +1,4 @@ -/* librist. Copyright © 2020 SipRadius LLC. All right reserved. +/* librist. Copyright © 2024 SipRadius LLC. All right reserved. * Author: Gijs Peskens <g...@in2ip.nl> * Author: Sergio Ammirata, Ph.D. <ser...@ammirata.net> * @@ -8,6 +8,8 @@ #include "librist/librist.h" #include "rist-private.h" #include <stdatomic.h> +#include "mpegts.h" +#include "endian-shim.h" #ifdef _WIN32 #include <windows.h> @@ -120,13 +122,31 @@ int send_counter = 0; char buffer[1316] = { 0 }; struct rist_data_block data = { 0 }; + srand(time(NULL)); /* we just try to send some string at ~20mbs for ~8 seconds */ while (send_counter < 16000) { if (atomic_load(&stop)) break; - sprintf(buffer, "DEADBEAF TEST PACKET #%i", send_counter); + // Make it a random size as a multiple of mpegts 188 bytes (max 7) and add sync byte, pid and flags + int random_num = (rand() % 7) + 1; + for(int ts = 0; ts < random_num; ts++){ + int offset = 188*ts; + struct mpegts_header * hdr = (struct mpegts_header *)&buffer[offset]; + memset(hdr, 0, sizeof(*hdr)); + hdr->syncbyte = 0x47; + // Random null pids + int random_bit = rand() % 2; + if (random_bit) { + hdr->flags1 = htobe16(0x1FFF); + SET_BIT(hdr->flags2,4); + } + else { + hdr->flags1 = htobe16(0x1111); + } + sprintf(&buffer[offset+sizeof(*hdr)+1], "DEADBEAF TEST PACKET #%i-%i", send_counter, ts); + } data.payload = &buffer; - data.payload_len = 1316; + data.payload_len = 188 * random_num; int ret = rist_sender_data_write(rist_sender, &data); if (ret < 0) { fprintf(stderr, "Failed to send test packet with error code %d!\n", ret); @@ -159,14 +179,18 @@ } int main(int argc, char *argv[]) { - if (argc != 5) { + if (argc != 5 && argc != 6) { return 99; } int profile = atoi(argv[1]); char *url1 = strdup(argv[2]); char *url2 = strdup(argv[3]); int losspercent = atoi(argv[4]) * 10; - int ret = 0; + int npd = 0; + int ret = 0; + + if (argc == 6) + npd = atoi(argv[5]); struct rist_ctx *receiver_ctx = NULL; struct rist_ctx *sender_ctx = NULL; @@ -202,6 +226,9 @@ sender_ctx->sender_ctx->simulate_loss = true; sender_ctx->sender_ctx->loss_percentage = losspercent; } + if (npd > 0) + rist_sender_npd_enable(sender_ctx); + pthread_t send_loop; if (pthread_create(&send_loop, NULL, send_data, (void *)sender_ctx) != 0) { @@ -223,14 +250,35 @@ receive_count = (int)b->seq; got_first = true; } - sprintf(rcompare, "DEADBEAF TEST PACKET #%i", receive_count); - if (strcmp(rcompare, b->payload)) { - fprintf(stderr, "Packet contents not as expected!\n"); - fprintf(stderr, "Got : %s\n", (char*)b->payload); - fprintf(stderr, "Expected : %s\n", (char*)rcompare); - atomic_store(&failed, 1); - atomic_store(&stop, 1); - break; + // Check entire mpegts structure + int tsindex = b->payload_len / 188; + for(int ts = 0; ts < tsindex; ts++){ + int offset = 188*ts; + uint8_t *payload = ((uint8_t*)b->payload + offset); + struct mpegts_header * hdr = (struct mpegts_header *)(payload); + if (hdr->syncbyte != 0x47) + { + fprintf(stderr, "Packet contents not as expected!\n"); + fprintf(stderr, "Sync Byte at index %d was %d instead of 0x47 with %zu bytes\n", ts, hdr->syncbyte, b->payload_len); + atomic_store(&failed, 1); + atomic_store(&stop, 1); + break; + } + // We only check for non-null segments or when null packet deletion is not enabled + // Otherwise our data would have been replaced with 0xff everywhere + if ((npd == 0 || (npd == 1 && be16toh(hdr->flags1) != 0x1FFF))) + { + // Check for string we wrote + sprintf(rcompare, "DEADBEAF TEST PACKET #%i-%i", receive_count, ts); + if (strcmp(rcompare, (char *)b->payload + offset + sizeof(*hdr) + 1)) { + fprintf(stderr, "Packet contents not as expected at index %i!\n", ts); + fprintf(stderr, "Got : %s (%zu/%d)\n", (char*)b->payload, b->payload_len, b->virt_dst_port); + fprintf(stderr, "Expected : %s\n", (char*)rcompare); + atomic_store(&failed, 1); + atomic_store(&stop, 1); + break; + } + } } receive_count++; rist_receiver_data_block_free2((struct rist_data_block **const)&b); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/test/rist/unit/srp_examples.c new/librist-v0.2.11/test/rist/unit/srp_examples.c --- old/librist-v0.2.10/test/rist/unit/srp_examples.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/test/rist/unit/srp_examples.c 2024-11-15 21:43:07.000000000 +0100 @@ -16,6 +16,11 @@ #define DEBUG_USE_EXAMPLE_CONSTANTS 1 #if HAVE_MBEDTLS +// musl's sched.h includes a prototype for calloc, so we need to make +// sure it's already been included before we redefine it to something +// that won't expand to a valid prototype. +#include <sched.h> + #define malloc(size) _test_malloc(size, __FILE__, __LINE__) #define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__) #define free(obj) _test_free(obj, __FILE__, __LINE__) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/oob_shared.c new/librist-v0.2.11/tools/oob_shared.c --- old/librist-v0.2.10/tools/oob_shared.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/oob_shared.c 2024-11-15 21:43:07.000000000 +0100 @@ -66,7 +66,7 @@ (void)addrlen; } -int oob_build_api_payload(char *buffer, char *sourceip, char *destip, char *message, int message_len) +int oob_build_api_payload(uint16_t *buffer, char *sourceip, char *destip, char *message, int message_len) { // We populate a valid IP header here but we do not really use it for any type of routing // We also populate a message that has the same information already present in the IP header but write it in text format @@ -81,7 +81,7 @@ int total_len = sizeof(struct ipheader) + message_len; ip->iph_len = htons(total_len); // Calculate the checksum for integrity since there is no packet recovery - ip->iph_chksum = csum((unsigned short *)buffer, total_len); + ip->iph_chksum = csum(buffer, (total_len + 1) / 2); return total_len; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/oob_shared.h new/librist-v0.2.11/tools/oob_shared.h --- old/librist-v0.2.10/tools/oob_shared.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/oob_shared.h 2024-11-15 21:43:07.000000000 +0100 @@ -38,7 +38,7 @@ }) void populate_ipv4_rist_header(unsigned short int address_family, unsigned char *recv_buf, ssize_t recv_bufsize, struct sockaddr * addr, socklen_t addrlen); -int oob_build_api_payload(char *buffer, char *sourceip, char *destip, char *message, int message_len); +int oob_build_api_payload(uint16_t *buffer, char *sourceip, char *destip, char *message, int message_len); char *oob_process_api_message(int buffer_len, char *buffer, int *message_len); #ifdef USE_TUN int oob_setup_tun_device(char *oobtun); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/prometheus-exporter.c new/librist-v0.2.11/tools/prometheus-exporter.c --- old/librist-v0.2.10/tools/prometheus-exporter.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/prometheus-exporter.c 2024-11-15 21:43:07.000000000 +0100 @@ -344,7 +344,7 @@ s->container[s->container_offset].rist_sender_peer_retransmitted_packets = s->counters.rist_sender_peer_retransmitted_packets += stats->retransmitted; s->container[s->container_offset].rist_sender_peer_bandwidth_bps = stats->bandwidth; s->container[s->container_offset].rist_sender_peer_retry_bandwidth_bps = stats->retry_bandwidth; - s->container[s->container_offset].rist_sender_peer_rtt_seconds= stats->rtt; + s->container[s->container_offset].rist_sender_peer_rtt_seconds= ((double)1 / (double)1000) * stats->rtt; s->container[s->container_offset].rist_sender_peer_quality = stats->quality; s->container[s->container_offset].updated = now; s->last_updated = now; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/rist2rist.c new/librist-v0.2.11/tools/rist2rist.c --- old/librist-v0.2.10/tools/rist2rist.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/rist2rist.c 2024-11-15 21:43:07.000000000 +0100 @@ -97,7 +97,7 @@ static int cb_auth_connect(void *arg, const char* connecting_ip, uint16_t connecting_port, const char* local_ip, uint16_t local_port, struct rist_peer *peer) { struct rist_ctx *receiver_ctx = (struct rist_ctx *)arg; - char buffer[500]; + uint16_t buffer[250]; char message[200]; int message_len = snprintf(message, 200, "auth,%s:%d,%s:%d", connecting_ip, connecting_port, local_ip, local_port); // To be compliant with the spec, the message must have an ipv4 header diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/ristreceiver.c new/librist-v0.2.11/tools/ristreceiver.c --- old/librist-v0.2.10/tools/ristreceiver.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/ristreceiver.c 2024-11-15 21:43:07.000000000 +0100 @@ -320,7 +320,7 @@ static int cb_auth_connect(void *arg, const char* connecting_ip, uint16_t connecting_port, const char* local_ip, uint16_t local_port, struct rist_peer *peer) { struct rist_callback_object *callback_object = (void *) arg; - char buffer[500]; + uint16_t buffer[250]; char message[200]; int message_len = snprintf(message, 200, "auth,%s:%d,%s:%d", connecting_ip, connecting_port, local_ip, local_port); // To be compliant with the spec, the message must have an ipv4 header @@ -430,7 +430,7 @@ stats = stats->next; } if (!stats) { - stats = calloc(sizeof(*stats), 1); + stats = calloc(1, sizeof(*stats)); stats->flow_id = stats_container->stats.receiver_flow.flow_id; *prev = stats; } @@ -799,6 +799,17 @@ goto next; } +#ifdef USE_TUN + if (strcmp(udp_config->prefix, "tun") == 0) { + if (!callback_object.tun) { + rist_log(&logging_settings, RIST_LOG_ERROR, "Detected 'tun://' usage in output url but '--tun' argument was not given\n"); + exit(1); + } + atleast_one_socket_opened = true; + goto next; + } +#endif + // Now parse the address 127.0.0.1:5000 char hostname[200] = {0}; int outputlisten; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/ristsender.c new/librist-v0.2.11/tools/ristsender.c --- old/librist-v0.2.10/tools/ristsender.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/ristsender.c 2024-11-15 21:43:07.000000000 +0100 @@ -334,7 +334,7 @@ } #endif struct rist_ctx *ctx = w->ctx; - char buffer[500]; + uint16_t buffer[250]; char message[200]; int message_len = snprintf(message, 200, "auth,%s:%d,%s:%d", connecting_ip, connecting_port, local_ip, local_port); // To be compliant with the spec, the message must have an ipv4 header diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/risturlhelp.h new/librist-v0.2.11/tools/risturlhelp.h --- old/librist-v0.2.10/tools/risturlhelp.h 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/risturlhelp.h 2024-11-15 21:43:07.000000000 +0100 @@ -18,7 +18,7 @@ " param cname=abcde arbitrary name for stream for display in logging\n" " param rtt-min=### minimum expected rtt\n" " param rtt-max=### maximum expected rtt\n" -" param verbose-level=# Disable -1; Error 3, Warning 4, Notice 5, Info 6, Debug 7, simulation/dry-run 100\n" +//" param verbose-level=# Disable -1; Error 3, Warning 4, Notice 5, Info 6, Debug 7, simulation/dry-run 100\n" " param timing-mode=# 0 = RTP Timestamp (default); 1 = Arrival Time, 2 = RTP/RTCP Timestamp+NTP\n" " Main and Advanced Profiles\n" " param aes-type=# 128 = AES-128, 256 = AES-256 must have passphrase too\n" @@ -33,16 +33,16 @@ " param weight=# default weight for multi-path load balancing. Use 0 for duplicate paths.\n" " param username=abcde Username to identify this peer during authentication\n" " param password=abcde Password corresponding to this peer's Username\n" -" param multiplex-mode=# Controls how rist payload is muxed/demuxed (-1=auto-detect, 0=rist/raw, \n" -" 1=vrt_src_port, 2=ipv4)\n" -//" param multiplex-filter=# When using mux-mode=ipv4, this is the string to be used for data filter.\n" -//" It should be written as destination IP:PORT\n" " Advanced Profile\n" " param compression=1|0 enable lz4 levels\n" "\n" "Usage: append to end of individual udp:// or rtp:// url(s) as ?param1=value1¶m2=value2...\n" " param miface=(device) device name (e.g. eth0) for multicast\n" " param stream-id=# ID number (arbitrary) for multiplex/demultiplexing steam in peer connector\n" +" param multiplex-mode=# Controls how rist payload is muxed/demuxed\n" +" (-1=auto-detect, 0=rist/raw, 1=vrt_src_port, 2=ipv4)\n" +//" param multiplex-filter=# When using mux-mode=ipv4, this is the string to be used for data filter.\n" +//" It should be written as destination IP:PORT\n" //" param rtp-timestamp=# carry over the timestamp to/from the rtp header into/from rist (0 or 1)\n" //" param rtp-sequence=# carry over the sequence number to/from the rtp header into/from rist (0 or 1)\n" //" param rtp-ptype=# override the default RTP PTYPE to this value\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/librist-v0.2.10/tools/srp_shared.c new/librist-v0.2.11/tools/srp_shared.c --- old/librist-v0.2.10/tools/srp_shared.c 2023-10-30 16:01:35.000000000 +0100 +++ new/librist-v0.2.11/tools/srp_shared.c 2024-11-15 21:43:07.000000000 +0100 @@ -172,8 +172,11 @@ struct stat buf; if (stat(srpfile, &buf) != 0) return; - - *generation = ((uint64_t)buf.st_mtim.tv_sec << 32) | buf.st_mtim.tv_nsec; + #ifdef _DARWIN_C_SOURCE + *generation = ((uint64_t)buf.st_mtimespec.tv_sec << 32) | buf.st_mtimespec.tv_nsec; + #else + *generation = ((uint64_t)buf.st_mtim.tv_sec << 32) | buf.st_mtim.tv_nsec; + #endif #endif if (!lookup_data || !hashversion)