Skip to content

Pull latest into cache update branch#432

Merged
mondain merged 121 commits intoreplace-cachefrom
main
Feb 1, 2026
Merged

Pull latest into cache update branch#432
mondain merged 121 commits intoreplace-cachefrom
main

Conversation

@mondain
Copy link
Copy Markdown
Member

@mondain mondain commented Feb 1, 2026

No description provided.

nateroe and others added 30 commits October 31, 2025 14:24
…lients use data channel to pass messages that the server never handles) [CS-117]
Demote logging about unhandled data channel messages (very loud if c…
AMF decided to allow negative length strings and arrays.  If the client
tries these shenanigans, just treat it as a 0 length object instead of
believing them.

Add a few checks to make sure we aren't reading past the end of the packet
if it ends too early.

Also don't let a client claim it's going to send a 2 billion arrays to
trick us into allocation 2 billion items to store them in.
…he context you're trying to unload does not exist
…meters,

return an empty Map instead of Collections.unmodifiableMap throwing an NPE
…tion,

if client is somehow null don't registerJMX() because that function needs
a working client object.
VINTs that were between 5 and 8 bytes were not being parsed correctly,
causing the parser to get out of sync with the stream.

To reproduce the original bug:

  - Take any Matroska element whose size field is encoded with a 7‑byte VINT (legal per EBML). Example: a Cluster element (ID =
    0x1F43B675) with a size of 0x20 bytes encoded as:
      - ID bytes: 1F 43 B6 75
      - Size bytes (7‑byte VINT): 02 00 00 00 00 00 20
          - The leading byte 0x02 is 00000010b, which in EBML means “length = 7 bytes, value bits = 0x000000000020”.
  - What the code does:
      - readVINT reads the first size byte fb = 0x02.
      - It sets len = fb >> 4, which is 0x0.
      - Because len is 0, it falls into the final else branch (“8‑byte VINT”), sets mask = MASK_BYTE_8, allocates an 8‑byte array,
        and reads 7 more bytes for this size.
      - The seven bytes it reads are the remaining 6 bytes of the size (00 00 00 00 00 20) plus the first byte of the element
        payload (because there were only 6 size bytes left). So the parser consumes one payload byte as if it were part of the
        size field.
  - Consequences:
      - The computed size is wrong (it’s based on 8 bytes instead of 7, and includes one payload byte).
      - The stream position is now off by one byte. The next call to parseTag starts in the middle of the element payload, so
        subsequent IDs/sizes are garbage. This typically leads to decoding failures, incorrect sizes, and eventually EOF/NPE/assert
        failures.
skip() calls InputStream.skip(), which is allowed to return 0, for example
if reading from a named pipe or fifo file that's blocked or trying to
read past the end of the file. If skip isn't working, try reading one
byte to either unstick it or at least advance the file pointer so it
doesn't end up with an infinite loop.

An alternative would be to just give up if input.skip() returns 0 because
I'm not sure recovery is possible.
If inputStream.read has an error, it returns -1.  Treat that like an error
instead of rewinding the read pointer by 1.
If parseTag fails it can return null.  Intentionally throw a meaningful
exception instead of an NPE.
Add missing break to co64 to stop it from falling through
getGenericType never maps double or char primitives to their wrappers
(checks Double.class/ Character.class instead of double.class/char.class),
so those primitives fall through and return the primitive type while other
primitives return wrappers.
InputStream readers for uint16/24/32 only checked the last byte for EOF.  If
the stream ended on the first or middle byte, the methods return a value
built from -1 bytes instead of throwing, leading to silent truncation and
incorrect protocol parsing (potentially accepting malformed handshakes).
single unmodifiable element containing the values collection, rather than a
list of the map’s values.  Changed ConversionUtils.convertMapToList in
ConversionUtils.java:212-214 to return a list of map values rather than a
single values collection entry.
without XML escaping.  Any <, &, or " characters in content produced
malformed XML and if not handled properly could allow injection of arbitrary
markup.
values requiring 5 bytes (>0x0FFFFFFF) overflow and drop the high byte,
producing incorrect LEB128 encodings.  Fixed by using the byte-array
encoder; throws when an encoding needs more than 4 bytes
1) Append mode overwrites instead of appending: WebmWriter never seeks to
    the end of the target file in append mode, so writeTag writes from
    offset 0 and destroys existing data

2) Existing file not truncated when rewriting: when append is false, the
    final copy writes new data to the destination but never truncates the
    file first.  If the destination already exists and is larger than the
    new content, stale bytes remain at the end, producing a corrupted WebM.

Fixed by:

1) Append mode now seeks to the end of the existing file before writing, so
    new data no longer overwrites from offset 0.

2) Rewrite mode truncates the destination before copying temporary data,
    preventing stale trailing bytes from older, larger files.
…alled correctly, and

if processing the results of FLVReader() throws an exception make sure to close the file so
it doesn't leak.
…trim

the URI down to the base application and room, with the format /app/room and
chop off any ?query or #anchor tags.  Instead it was converting
"/app/room?q=a" to "/app" instead of "/app/room".
…ope for

a path.  If the path doesn’t match a registered application (typoed URL,
unregistered app), don't throw a NoSuchElementException during handshake.
…istener

    with listener.getClass().isInstance(clazz), but isInstance expects an
    object, not a Class.  This always returned false, so listeners were never
    detected.  As a result, code that relies on this check (e.g., avoiding
    duplicate registration or verifying protocol handler availability)
    silently failed. Check adjusted to match function return type.
…ecking

that it's not null, since it could be client controlled.

Fix a similar issue in service/Call.java's read/writeExternal to check
serviceName and serviceMethodName before using them.

In ReflectionUtils, findMethod now checks that methodName and arguments
aren't null before referencing them.
…c and, if negative, only added 256.

Negative 24-bit values were not sign-extended correctly, so decoded numbers were wrong.
Fixed by sign-extending the high byte.
…ute with the

default value instead of fetching it.
…sent

(meta.getMetaCue() returns null), the subsequent metaArr.length access
throws NullPointerException, so injecting metadata into files without
cue points fails.
null, but then would dereference it anyway on the return line.  Just return
false if it's null.
mondain and others added 24 commits January 1, 2026 14:46
…olEncoder.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…olEncoder.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…olEncoder.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…olEncoder.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
PlayEngine changes:
- Track audio and video base timestamps separately for late subscribers
- Both audio and video now start at ts=2 for proper A/V sync
- Reorder playLive() to send audio config before keyframe (DTS ordering fix)
- Add debug logging for video frame delivery path

RTMPConnection changes:
- Reduce BytesRead acknowledgement interval from 1MB to 128KB
- More frequent acknowledgements improve encoder compatibility
- Add debug logging for BytesRead messages

RTMP codec improvements:
- Enhanced extended timestamp handling for timestamps >= 0xFFFFFF
- Per-channel timestamp offset tracking for discontinuity compensation
- Improved timestamp delta calculations in encoder

Debug logging additions:
- ClientBroadcastStream: video reception and livePipe push logging
- VideoFrameDropper: state transition and frame drop decision logging
- TestRTMPUtils: comprehensive tests for RTMP utility methods
Proposed 2.0.26 release with RTMP encode/decode fixes
- Fix race condition in WebSocketPlugin.setApplication() by using
  computeIfAbsent for atomic manager creation and initialization
- Add getApplication() getter to WebSocketScopeManager to expose appScope
- Add null guard in makeScope(IScope) to prevent NPE
- Normalize trailing slashes in paths (e.g., "/live/" -> "/live") in both
  DefaultServerEndpointConfigurator.modifyHandshake() and
  WebSocketScopeManager.getScope() for consistent scope lookups
- Add null checks before putting scope in ConcurrentHashMap user properties
- Improve scope lookup to use manager.getApplication() before plugin lookup
Two issues were causing chunk stream desynchronization in Red5-to-Red5
cluster communication:

1. Type 0 header decoding did not reset extended=false when wire timestamp
   dropped below MEDIUM_INT_MAX (16777215). This caused the flag to be
   incorrectly inherited from previous headers, making Type 3 chunks read
   4 extra bytes when they shouldn't.

2. A "compatibility check" in Type 3 handling used decoded timestamp values
   (which include discontinuity offsets) instead of wire values, causing
   false positives that read extra bytes.

Also documented that RTMPProtocolDecoder.decodeBuffer() already calls
compact() in its finally block - callers should NOT compact again as
double-compact corrupts buffer positions.

Fixes:
- Add else clause to Type 0 to reset extended=false when timestamp < MEDIUM_INT_MAX
- Remove faulty compatibility check from Type 3 that checked adjusted values
- Add comments in Mina decoders warning against double-compact
- Add debug logging for Type 3 extended timestamp encoding
- Add unit test for extended-to-non-extended timestamp transition
@mondain mondain merged commit 02b21bd into replace-cache Feb 1, 2026
mondain added a commit that referenced this pull request Feb 1, 2026
Merge pull request #432 from Red5/main
@mondain mondain review requested due to automatic review settings March 23, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants