librist - Reliable Internet Stream Transport
============================================

A library implementing the Video Services Forum (VSF) Technical
Recommendations TR-06-1 (Simple Profile) and TR-06-2 (Main Profile).


Changes for 0.2.15 (2026-05-14):
--------------------------------

ABI/API:
  - ABI version 10:3:6 (soversion 4, binary-compatible with 0.2.14)
  - API version 4.7.0 (unchanged)

  Security release. Existing 0.2.14 installations remain
  binary-compatible; downstream consumers do not need to recompile.

Security Fixes:

  Receive-side parsers and key handling were audited end to end. Each
  fix below is independent.

  Receive path / RTCP:
  - rist-common: bounds-check the RTP and RTP-extension headers.
    The earlier check only covered the 4-byte reduced port subheader;
    a truncated packet underflowed payload.size to ~SIZE_MAX which
    then drove a malloc(len + 32) on the receiver enqueue path.
  - rist-common: harden the RTCP dispatcher. Off-by-one in
    bytes_left, integer overflow in 4*(1+records) (CPU spin on a
    single packet), and an SDES handler that let 255 bytes be
    memcpy'd into a 128-byte struct member, overrunning the adjacent
    peer config/key state.
  - rist-common: bound the XR block parser, clamp the on-the-wire
    length to what we received, and guard the DLRR delay subtraction
    so it can no longer pin last_rtt near UINT64_MAX (which would
    permanently disable NACK timing on the peer).
  - rist-common: validate the sender NACK record count before
    iterating. ntohs(rtcp->len) - 2 underflowed to ~65K on a
    malformed feedback packet, enqueueing OOB bytes as retransmit
    requests and leaking them back to the peer.
  - rist-common: add the missing return after the VSF length check,
    and derive odd_nonce from the actual nonce byte rather than
    GRE flags1 (the latter silently disabled the OTF passphrase
    rotation feature on the receive side).
  - rtcp: guard the RR and echo-response RTT subtractions and
    size-check the SR / echo-request / echo-response casts (same
    RTT-underflow primitive as above on the RR/echo paths).
  - rtcp: correct the XR echoreq RTCP length field per RFC 3550;
    receivers were reading 4 bytes past the actual XR block.
  - mpegts: bound NPD expansion to the 7-packet wire encoding.
    expand_null_packets used attacker-controlled payload_len and
    npd_bits to drive ts_count and write up to 11 KB into a 10 KB
    recv_npd buffer (overrunning into the adjacent RTCP TX buffer),
    and shifted by a negative amount when ts_count > 7.
  - gre: zero-init keepalive info on short packet and check return,
    otherwise a truncated keepalive disclosed stack memory through
    the user logging callback.
  - udpsocket: NUL-terminate the URL hostname after strncpy so
    udpsocket_resolve_host cannot over-read.

  PSK / AES-CTR:
  - crypto: reject zero-nonce PSK packets instead of skipping
    decryption. The previous early-return left the recv buffer
    untouched and the caller treated the attacker's plaintext as a
    freshly-decrypted Main Profile packet, bypassing the configured
    PSK per packet. Pre-auth, single packet.
  - crypto: correct nettle AES-CTR dispatch for 128/192-bit keys.
    AES-128 was using nettle_aes192_encrypt against an aes128
    context; the AES-192 case was missing entirely, leaving an
    uninitialised function pointer hot on the EAP password-rotation
    path.

  EAP / SRP:
  - eap: validate EAPOL/EAP/SRP-TLV lengths end to end. The body
    length check was inverted and inner dispatchers walked past the
    recv buffer with attacker-supplied lengths, exfiltrating heap
    bytes through username copies and AES-CTR rewrites. Adjacent
    fixes cover EAP header / dispatch / passphrase-flags reads.
  - eap: NULL-check auth_ctx and propagate handle_A failure (notably
    A == 0 mod N) so a rejected SRP exchange actually fails auth
    instead of sending an uninitialised B back to the client. NULL
    check the SRP client ctx and propagate the int-typed return of
    the A/B writers (a -1 wrapped to ~SIZE_MAX and crashed on the
    last_pkt malloc cache path).
  - eap: bound rist_eap_send_passphrase to the destination buffer;
    an over-long passphrase from the API or YAML config overran
    ctx->unsollicited_passphrase into adjacent heap fields used by
    the periodic retransmit.
  - eap: rate-limit the EAP_CODE_FAILURE restart loop. The handler
    unconditionally called eap_reset_data + log + EAPOL_START with
    no retry counting, so a spoofed FAILURE per round-trip kept us
    bouncing through reset+restart forever.
  - eap: write the empty server-name placeholder into outpkt rather
    than pkt (pure copy/paste typo that corrupted the recv buffer
    on every successful identity response).
  - srp: propagate failure when the client A, server B, or u is
    congruent to 0 mod N. The checks existed but the failure path
    left ret==0 so the caller continued the exchange. Auth bypass
    primitive on both sides.

  PRNG:
  - crypto: route prand_u32 through the CSPRNG. The previous
    implementation called rand() seeded with a wall-clock NTP
    timestamp; the result is used for the PSK GRE nonce (input to
    PBKDF2), the EAP identifier and the peer SSRC. Reuse the mbedTLS
    CTR-DRBG / GnuTLS RNG that already backs SRP key generation.
  - crypto: fix operator-precedence bug in random_get_string and
    add an upper bound on the local rand buffer. Affected callers
    that ask for a runtime-derived password.

Hygiene (not security-impacting on their own but shipped in the same
release):
  - flow: handle realloc/calloc failure on the peer-list growth path
    and rist_receiver_missing; correct two log format strings
    (uint32_t printed with PRIu64; pointer where a PRIu32 was due).
  - libevsocket: preserve the global context list when removing the
    head; ctx_del previously cleared CTX_LIST instead of advancing
    it to c->next.
  - eap, logging, udpsocket: NULL-check the malloc/calloc results
    that were dereferenced unconditionally; free the calloc'd ctx
    on pthread_mutex_init failure in eap_clone_ctx; close the bound
    socket on the multicast-join failure leg.
  - network: on the GNU/Hurd MAC-address path, check socket() and
    close it on the getifaddrs() failure leg.

Additional fixes from the VideoLAN security audit:

  Independent receive-side / EAP / SRP audit shared by VideoLAN.
  The findings already covered above are not re-listed; the items
  below close the residual gaps.

  EAP / SRP:
  - eap: ignore EAP_REQUEST_IDENTITY once we're past
    EAP_AUTH_STATE_SUCCESS so a single forged identity request can
    no longer tear an established session down and re-emit the
    configured username on the wire.
  - eap: refuse RESPONSE/IDENTITY on the authenticatee side
    (lookup_func is NULL there per the calloc setup path; the
    handler used to deref it unconditionally).
  - eap: free verifier_data on every exit from
    process_eap_response_identity. Three error paths returned -1
    before reaching the cleanup block, leaking the four heap
    allocations the verifier lookup callback handed back.
  - srp: jump to failed: instead of returning out of
    BIGNUM_WRITE_BYTES when MPI write fails inside calc_x; the
    return -1 path leaked hash_data.
  - srp: check librist_crypto_srp_hash_bignum return in
    calculate_m. The helper returns -1 (and leaves the output
    buffer untouched) when the bignum exceeds its 1024-byte
    staging buffer; the unchecked path XOR'd uninitialised stack
    into the SRP transcript.
  - srp: BIGNUM_INIT k and B in the authenticator constructor.
    Relying on calloc-zeroed mbedtls_mpi state happened to work
    today but the public mbedTLS contract requires explicit init.
  - srp: bound A and B operand sizes against N before exp_mod.
    handle_A and client_handle_B accepted any length from the
    wire; mbedtls_mpi_exp_mod runtime grows with operand size.
  - srp: NULL the caller's *bytes_s/*bytes_v in _create_verifier
    failure paths so eap_reset_data does not double-free them.
  - srp: capture mbedtls_mpi_fill_random return when generating
    the salt; the previous `if (ret != 0)` re-checked the prior
    BIGNUM_FROM_STRING.
  - srp: repair the !USE_SHA_RET branch of librist_crypto_srp_hash
    (referenced symbols from a different function and was missing
    its trailing semicolon).
  - srp: drop the sub-1024-bit RFC 5054 groups (NG_512, NG_768).
    The enum was internal; the unit-test fixture that wanted the
    deterministic 512-bit exchange now inlines the constants.

  PSK / AES-CTR:
  - psk: fail closed when PBKDF2 setup fails on the mbedTLS path.
    mbedtls_md_setup / mbedtls_pkcs5_pbkdf2_hmac errors used to
    fall through into mbedtls_aes_setkey_enc with the
    stack-allocated aes_key buffer in undefined state.
  - psk: don't let an attacker-chosen nonce reset the bad-packet
    lockout. _librist_crypto_psk_decrypt now keeps bad_decryption
    set across nonce rolls so the five-bad-packets cap is no
    longer trivially bypassed by sending a different nonce on
    every shot.
  - psk: use memcpy for the GRE nonce load instead of a punned
    uint32_t cast (strict-aliasing UB; faulted on architectures
    that require aligned uint32_t loads).

  Receive path:
  - rist-common: lift the rist_rtp_hdr size check above the
    Simple/REDUCED conditional so Main-profile FULL/EAPOL paths
    can no longer read past recv_bufsize.
  - udp: size the NPD scratch buffer for the real worst case
    (7 * 204 + sizeof(rist_rtp_hdr_ext)). The previous 6 * 204 + 4
    was four bytes short for the (count == 7, suppressed == 1)
    output and let suppress_null_packets smash four bytes of
    stack past tmp_buf.
  - rist-common: cast keepalive json_len to int for %.*s. size_t
    via varargs is undefined per the C standard.

  Flow / threading:
  - flow: take f->mutex when growing peer_lst; the realloc could
    move storage and concurrent walkers (rist_best_rtt_index, the
    output thread, stats) read peer_lst without synchronization.
  - flow: cap receiver flows at RIST_MAX_FLOWS (256) and walk
    FLOWS under flows_lock. Without a cap an attacker that can
    land traffic on a receiver can exhaust memory by walking the
    32-bit flow_id space.
  - flow: NULL-check the dataout_fifo_queue calloc; the
    data-output thread used to write into it unconditionally.

  TUN / RTCP TX / utility:
  - tun_linux, tun_darwin: bounds-check prefix_len before computing
    the netmask. prefix_len < 0 hit undefined behaviour in C and
    prefix_len == 32 produced a 32-bit shift on a uint32_t (also
    UB).
  - tun_darwin: parse the utun unit suffix with strtoul, not atoi,
    with full validation; falls back to "let the kernel pick" on
    parse failure.
  - rtp: clamp SDES name_len to 255 before computing sdes_size so
    the on-the-wire length byte and the actual bytes copied stay
    in agreement.
  - rist-common: make compare() return a real three-way result
    (qsort's contract is < 0 / 0 / > 0; the previous boolean cast
    was undefined per POSIX).
  - rist-common: pick the actual median in recalculate_clock_offset
    (the index was biased high by one).

Bug Fixes:
  - rist-common: initialize peer->sd to -1 in peer_initialize so a
    DNS resolution failure no longer leaves a zero socket
    descriptor wired up to the event loop, which on Windows turned
    into an infinite POLLERR loop and on Unix could attach the RIST
    state to fd 0 (stdin). (!312, Yannick Le Roux)
  - logging: check log_socket >= 0 instead of just non-zero in the
    rist_log_impl UDP path, matching the LOGGING_SETTINGS_INITIALIZER
    sentinel (the early-exit was tightened in f7ace4d but the send
    branch still treated 0 as a valid fd). (!313, Daisuke Matsunami)
  - stats: emit sender peers under a "peers" array. The previous
    shape used "peer" as the key for every peer object, producing
    invalid JSON and silently dropping all but one peer in strict
    parsers. (#206, Manuel Alejandro)

Tools:
  - prometheus-exporter: implement rist_prometheus_parse_sender_stats.
    The hook for ristsender's JSON stats callback was a TODO stub, so
    sender-side rist_sender_peer_* gauges/counters never showed up at
    the scrape endpoint. The parser now walks the new "peers" array
    and feeds rist_prometheus_handle_sender_peer_stats; metric names
    and shape are unchanged from the receiver-callback path.
    (closes the second half of #206)
  - ristsender: drop a duplicate rist_sender_stats_callback_set call
    in setup_rist_peer that overwrote the per-instance arg with NULL,
    breaking sender attribution when more than one sender ran in the
    same process.
  - udp2udp: log a one-shot warning when --metrics is enabled noting
    that the relay produces no rist_* series (it uses librist only
    for URL parsing and the httpd shell).

Windows / MinGW Build:
  - rist.c: return integer (not NULL) from the PTHREAD_START_FUNC
    bodies. The macro expands to a DWORD __stdcall function on
    Windows without HAVE_PTHREADS, which gcc14 rejected.
  - meson: always probe clock_gettime via has_header_symbol on
    Windows, not only when have_mingw_pthreads=true. Modern
    mingw-w64 ships clock_gettime as a static inline in <time.h>
    regardless of winpthreads, so contrib/time-shim.c collided
    with the toolchain definition on the default build.
  - rist-common: drain WSAECONNRESET with a real recvfrom buffer
    on the rist_peer_sockerr POLLERR path. The previous NULL-buffer
    call returned WSAEFAULT and left the indication in the socket
    queue, causing WSAPoll to fire POLLERR in a tight loop and
    flood the log with "Socket error!" whenever a peer went away.
    (#205, Manuel Alejandro)
  - tools: centralize the strtok_r/strtok_s shim in a header so
    rist2rist (and any future tool that needs strtok_r) builds on
    MinGW / MSVC. ristsender and ristreceiver had inline shims;
    rist2rist's recent multi-peer bonding work added strtok_r
    without one and failed to link. (#207, Thierry Lelegard)

Changes for 0.2.14 (2026-04-25):
--------------------------------

ABI/API:
  - ABI version 10:2:6 (soversion 4, binary-compatible with 0.2.13)
  - API version 4.7.0 (unchanged)

  Maintenance release. No public API or ABI signature changes.
  Existing 0.2.13 installations remain binary-compatible; downstream
  consumers do not need to recompile and relink.

Bug Fixes:

  - fix(sender): serialize retry-queue dequeue under peerlist_lock
    to avoid a use-after-free. The retry-queue cleanup path could
    race with peer teardown and dereference a peer that had already
    been freed on a sibling thread, occasionally producing a sender
    crash under sustained NACK pressure with multi-peer
    configurations. The dequeue is now performed with the peerlist
    lock held for the full critical section.
  - fix(macos): honor the -1/errno contract in the time-shim and
    zero-initialize the timespec before calling clock_gettime_osx.
    rist__get_system_boottime() previously returned the errno value
    as its result instead of -1, which silently produced corrupted
    NTP timestamps on macOS in restricted-syscall environments
    (containers, sandboxes that block sysctl(KERN_BOOTTIME)). The
    function now returns sysctl()'s actual return value, and
    timestampNTP_u64() / timestampNTP_RTC_u64() defensively
    zero-init their timespec so a clock_gettime failure can no
    longer leak uninitialized stack into the time arithmetic and
    falsely trip the "stream is dead" timeout.

Windows / MSVC / MinGW:

  - contrib/poll_win: fix the Windows poll() emulation busy-spinning
    at 100% CPU when the watched fd set contains only sockets
    (the common case for librist). The previous implementation fell
    through to a 0 ms select() loop whenever no pipe/handle fds were
    present; the timeout argument is now correctly honoured in the
    sockets-only path.
  - msvc: round out the contrib stdatomic shim and select native
    C11 atomics where the toolchain supports them. Restores
    correct atomic_uint_fast64_t behaviour on MSVC builds where
    earlier shim coverage left some operations as plain reads /
    writes, which (under heavy contention) could let the receiver
    flow's last_pkt_received drift and produce false stream-dead
    events on Windows.

Tools:

  - tools/rist2rist: add multi-peer bonding (multiple input or
    output URLs on the command line), MPEG-TS Null Packet Deletion
    (NPD), and Prometheus metrics export. rist2rist can now serve
    as a load-balancing relay sitting close to the source of truth,
    where small recovery buffers and large retry queues let
    downstream receivers absorb network impairments without
    inflating end-to-end latency.

Contrib (bundled mbedtls):

  - contrib/mbedtls: refresh bundled source from 2.26.0 to 2.28.10
    (last LTS release of the 2.x series, 2025-03-24). 2.28.x is
    strictly ABI-compatible with 2.26.x, so no librist code change
    was required. Notable mbedtls fixes pulled in:
      * CVE-2025-27809 (TLS server impersonation via missing
        mbedtls_ssl_set_hostname)
      * CVE-2025-27810 (TLS 1.2 Finished message corruption on
        allocator/HW failure)
      * CVE-2024-45157 (PSA HMAC_DRBG selection regression)
      * Multi-year accumulation of fixes in AES, ECP, MPI, RSA,
        PK, PKCS5, bignum and the new constant_time.c
        side-channel-hardened primitives.
    librist itself only consumes the classic mbedtls crypto API
    (AES-CTR, CTR-DRBG, entropy, SHA-256, PBKDF2, MPI), so the
    upgrade is a drop-in replacement for the bundled path. The
    system-mbedtls build path (-Dbuiltin_mbedtls=false, the
    default when a system libmbedcrypto is detected) is not
    touched by this commit.
  - contrib/mbedtls: widen the hardclock gate from defined(_MSC_VER)
    to defined(_WIN32) in the bundled timing.c, so MinGW and
    Clang-Windows builds now also pick up the
    QueryPerformanceCounter implementation of
    mbedtls_timing_hardclock().

Contributors:
  - Sergio Ammirata


Changes for 0.2.13 (2026-04-18):
--------------------------------

ABI/API:
  - ABI version 10:1:6 (soversion 4, binary-compatible with 0.2.12)
  - API version 4.7.0 (unchanged)

Build Fixes:

  Platform build-fix release. No changes to the RIST protocol, public
  API, or ABI signatures. All existing 0.2.12 installations remain
  binary-compatible; downstream consumers do not need to recompile.

  This release is only relevant if you build librist targeting one of
  the platforms listed below. Native Linux, native macOS, FreeBSD,
  and classic Win32 builds with MSVC are unaffected.

    Windows desktop built with mingw-w64 (gcc or llvm-mingw):
    - meson: detect clock_gettime with has_header_symbol
      v0.2.12's probe used cc.has_function('clock_gettime'), which
      does not resolve the static inline definition shipped by
      mingw-w64's <pthread_time.h>. The resulting HAVE_CLOCK_GETTIME=0
      caused contrib/time-shim.h to emit a conflicting extern
      declaration and broke any downstream build with strict warnings
      ("redefinition of 'clock_gettime'"). Switching to
      cc.has_header_symbol detects the inline correctly.

    Windows UWP (i686/x86_64/aarch64-w64-mingw32 UWP toolchains):
    - Also fixed by the has_header_symbol probe above.
    - network.c: replace GetAdaptersInfo with GetAdaptersAddresses
      _librist_network_get_macaddr() called GetAdaptersInfo, which is
      not part of the UWP (WINAPI_FAMILY_APP) API surface;
      llvm-mingw's UWP iphlpapi import library does not export it,
      so UWP consumers of librist.a failed to link with "undefined
      symbol: _GetAdaptersInfo". Replaced with GetAdaptersAddresses,
      supported on classic Win32 desktop and on UWP since Windows 8.

    Embedded Apple SDKs (iOS, tvOS, watchOS, visionOS, all archs):
    - tun_darwin.c: build as stubs on non-macOS Apple platforms
      The v0.2.12 TUN support was guarded by #ifdef __APPLE__, but
      <sys/kern_control.h> and <net/if_utun.h> only ship with the
      macOS SDK. Every non-macOS Apple cross-build failed with
      "fatal error: 'sys/kern_control.h' file not found", and simply
      gating off the file produced a later link error because
      src/rist.c and src/rist-common.c call rist_tun_read /
      rist_tun_write unconditionally. Pull in <TargetConditionals.h>,
      restrict the utun implementation to
      defined(__APPLE__) && TARGET_OS_OSX, and add a second
      #elif defined(__APPLE__) branch with stub implementations of
      the seven public rist_tun_* entry points returning -1, matching
      the pattern src/tun_win.c already uses on Windows. Real utun
      support on macOS is unchanged.

    macOS used as a cross-build HOST:
    - meson: skip Homebrew prefix lookup for cross-builds
      The Homebrew fallback that adds /opt/homebrew or /usr/local
      include paths was running unconditionally on any Darwin host.
      Macs cross-compiling librist for iOS, tvOS, visionOS, Android,
      or mingw could hang or fail at configure. Gated the lookup on
      a native macOS build. Native-macOS-for-macOS builds are
      unaffected.

Contributors:
  - Sergio Ammirata

No source-file changes outside of meson.build, src/network.c, and
src/tun_darwin.c.


Changes for 0.2.12 (2026-04-17):
--------------------------------

ABI/API:
  - ABI version 10:0:6 (soversion 4, binary-compatible with 0.2.11)
  - API version 4.7.0

New Features:
  - Cross-platform TUN support moved into the library
    (rist_tun_open/close/read/write/set_ip/set_mtu/bring_up)
    macOS (utun), Linux (/dev/net/tun), Windows (stub)
  - data_fd forwarding API: rist_sender_data_fd_set,
    rist_receiver_data_fd_set, rist_data_fd_stats_get
    librist reads/writes directly to the fd, no application
    code in the data path (works with sockets, FIFOs, TUN fds)
  - New risttunnel tool: point-to-point IP tunnel over RIST
  - YAML config file support for ristsender/ristreceiver with native parser
  - Receiver session timeout API and --session-timeout CLI option
  - Peer statistics in receiver output
  - Multicast interface (miface) in sender peer statistics JSON
  - avg_buffer_time field exposed in receiver_flow stats struct
  - New udp2udp tool for UDP relay
  - Profile selection (--profile) in rist2rist
  - Sender input queue statistics
  - MPEG-TS null packet suppression byte tracking
  - Differentiated bitrate tracking and sender stats API

Bug Fixes:
  - Fix sender queue full detection: replace wrap-unsafe index
    arithmetic (which silently misfired on ring-buffer wraparound)
    with a size-vs-max comparison. Prevents in-flight retransmit
    buffers from being silently overwritten under sustained load.
  - Fix OOB main-profile data delivery: rist_send_seq_rtcp no
    longer strips the first 4 bytes of zero-header OOB packets,
    and rist_oob_dequeue now iterates child peers when the OOB
    buffer references a listener peer (matching main-channel
    behaviour instead of failing silently).
  - Fix receiver crash on configurable RTT multiplier path
  - Fix bogus lost-packet counters
  - Fix premature stream stop on ECHO timeout for single-path (closes #196)
  - Fix multi-sender queue issues (static buffer_size moved to context)
  - Thread-safe FIFO access in rist_receiver_data_read2
  - Fix memory leaks (authentication failures, sender queue)
  - Fix OpenMetrics response: add missing trailing EOF line
  - Fix rist_client_flow_quality metric unit
  - Fix OpenMetrics Content-Type header for Prometheus compatibility
  - Fix RTT min/max invalid values
  - Fix const correctness in URL parameter parsing
  - Fix signed/unsigned comparison statements
  - Fix missing strings.h include in yamlparse.c
  - Fix clock used when processing RR with lsr older than last SR
  - Fix -Wmisleading-indentation warning in receiver FIFO overflow path
  - Fix tools build on macOS/Windows/FreeBSD: include endian-shim.h
    for be16toh in ristsender.c and ristreceiver.c
  - Fix tools build: always compile tunnel_interface/tun_mode into
    rist_tools_config_object (consumers reference them unconditionally)
  - Fix missing_counter bookkeeping: track queue length instead of
    NACK-sent count. Previously the counter stayed at 0 on paths that
    never emit NACKs (e.g. simple-profile multicast), causing the
    missing_queue JSON stat to under-report and the congestion guard in
    receiver_mark_missing to never trip.
  - Fix build-only-platform-matching TUN source file; previously the
    non-matching src/tun_*.c were compiled into an empty translation
    unit and tripped -Werror=pedantic on Ubuntu/MinGW.
  - Fix risttunnel build on MinGW: include <windows.h> for Sleep().

Improvements:
  - Refactored sender queue management for better memory efficiency
  - Improved UDP send reliability with EAGAIN retry
  - Improved cname buffer safety
  - Refactored flow timeout semantics

Build System:
  - TUN support is now always compiled; removed the use_tun meson option
  - CI: drop -Duse_tun=true flag from ubuntu build job
  - Fix false positive mbedtls detection in meson build
  - Use MbedTLS cmake config module
  - Check brew exists before calling (macOS)
  - Fix compiler warnings in aes.h (Steve Lhomme)

Acknowledgements:
  - Dave Evans for RR clock fix
  - Steve Lhomme for aes.h warning fixes
  - Laur for the receiver FIFO misleading-indentation report


Changes for 0.2.11 (2024-11-15):
--------------------------------

New Features:
  - Ephemeral listening ports support (add/remove ports after initialization)
  - New function rist_sender_npd_get for null packet deletion status
  - New function rist_peer_get_cname to extract peer's private cname
  - Enhanced CI test application with packet integrity checks

Bug Fixes:
  - Fixed potential socket deadlock condition under MS Windows
  - Fixed ristsender confusion with multicast addresses sharing destination port
  - Fixed compile warnings under different C++ versions
  - Fixed theoretical IP checksum calculation issue
  - Fixed ristreceiver closing when tun://@ used in output URL
  - Fixed deadlock condition on FIFO overflow
  - Fixed invalid verbose-level parameter handling
  - Fixed binding to raw UDP socket
  - Fixed memory allocation order in stats structures
  - Fixed Mac homebrew arm64 build
  - Fixed null packet deletion
  - Fixed units on sender Prometheus stats
  - Fixed keepalive packet data corruption bug
  - Fixed improper RTP/RTCP classification (affected ST2110)
  - Fixed flow timeout to follow session timeout
  - Updated peer config timing_mode field handling

Build:
  - Updated meson version to avoid deprecated items

Acknowledgements:
  - Special thanks to Thierry Lelegard for null packet deletion bug fix


Changes for 0.2.10 (2023-10-30):
--------------------------------

  - Development branch merge with accumulated fixes and improvements


Changes for 0.2.9 (2023-10-11):
-------------------------------

Bug Fixes:
  - Fix compilation on 32-bit systems
  - Fix regression in stats obj RTT value
  - Remove unneeded locking in buffer scaling
  - Fix "too old packages" error due to buffer scaling
  - Fix empty buffer time check
  - Disable buffer negotiation when sender max buffer < receiver buffer
  - Fix deadlock caused by wrong lock order when removing peers
  - Fix building Prometheus code against older libmicrohttpd
  - Fix compilation on Hurd


Changes for 0.2.8 (2023-08-22):
-------------------------------

New Features:
  - SRP (Secure Remote Password) passphrase exchange
  - Passphrase changing support via U1 bit on M1/M2 packets
  - Fully implemented passphrase changing on multicast

Bug Fixes:
  - Add GRE check for bit 1 and GRE Ver set to 0
  - Fix SIGSEGV when peer_rtcp pointer is null

Improvements:
  - Refactored peer matching
  - Refactored cryptographic randomness from SRP
  - Added peer lock for thread safety
  - Default PSK keysize to 256 if not set


Changes for 0.2.7 (2022-04-07):
-------------------------------

New Features:
  - Multiplexing support
  - TUN (tunnel) interface support


Changes for 0.2.6 (2021-07-22):
-------------------------------

Improvements:
  - Move per-packet messages to debug level to prevent log flooding
  - Release data earlier when real-time in buffer exceeds 1.1x buffer duration
  - Drop stale packets older than 2x buffer duration


Changes for 0.2.5 (2021-07-20):
-------------------------------

  - Maintenance release with minor fixes


Changes for 0.2.4 (2021-06-25):
-------------------------------

  - Maintenance release with stability improvements


Changes for 0.2.3 (2021-06-22):
-------------------------------

  - Maintenance release with bug fixes


Changes for 0.2.2 (2021-06-16):
-------------------------------

  - Maintenance release


Changes for 0.2.1 (2021-06-10):
-------------------------------

  - Stability fixes for initial public release


Changes for 0.2.0 (2021-05-12):
-------------------------------

Initial official public release of librist.

Core Features:
  - Full support for VSF TR-06-1 (Simple Profile)
  - Partial support for VSF TR-06-2 (Main/Advanced Profile):
    * PSK Encryption (AES 128 and 256)
    * Bidirectional connection initiation
    * Multipath support (load balanced or redundant link bonding)
    * One-to-many distribution (media server mode)
    * Tested packet recovery up to 50% continuous loss
    * Jitter-tolerant output timing

Tools:
  - ristsender - RIST sender application
  - ristreceiver - RIST receiver application
  - rist2rist - RIST relay/proxy application

Platform Support:
  - Linux, macOS, Windows, FreeBSD
  - Cross-compilation support via meson


Project Information:
--------------------

Website: https://code.videolan.org/rist/librist
License: BSD 2-Clause "Simplified" License
