Skip to content

Commit 8ae0506

Browse files
authored
Merge pull request #338 from Red5/bug/R5SI-786
Bug/r5 si 786
2 parents a515f85 + daaff41 commit 8ae0506

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

client/src/test/java/org/red5/client/net/rtmp/codec/RTMPClientProtocolDecoderTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import static org.junit.Assert.*;
44

5+
import java.util.List;
6+
57
import org.apache.mina.core.buffer.IoBuffer;
68
import org.junit.After;
79
import org.junit.Before;
@@ -89,4 +91,16 @@ public void testDecodeBufferExTS() {
8991
assertTrue(packet.getMessage() instanceof AudioData);
9092
}
9193

94+
@Test
95+
public void testExtendedTImestampPartialPacket() {
96+
//Buffer contains 2 complete objects and 1 incomplete object.
97+
byte[] buf = IOUtils.hexStringToByteArray("03ffffff00004b090100000005584fce270100002800000042419e1e45152c236f0000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000030000049c03ffffff000008080100000005584fd1af01211004608c1c03ffffff000049090100000005");
98+
RTMPConnection conn = RTMPConnManager.getInstance().createConnection(RTMPMinaConnection.class);
99+
conn.setStateCode(RTMP.STATE_CONNECTED);
100+
RTMPClientProtocolDecoder decoder = new RTMPClientProtocolDecoder();
101+
List<Object> objects = decoder.decodeBuffer(conn, IoBuffer.wrap(buf));
102+
//RTMPDecodeState state = conn.getDecoderState();
103+
assertTrue(objects.size() == 2);
104+
105+
}
92106
}

common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -364,24 +364,14 @@ public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in,
364364
// represents "packet" header length via "format" only 1 byte in the chunk header is needed here
365365
int headerLength = RTMPUtils.getHeaderLength(headerSize);
366366
headerLength += chh.getSize() - 1;
367-
if (in.remaining() < headerLength || in.remaining() < 3) {
367+
//If remaining bytes is less than known headerLength return null and set decoder state.
368+
//This length does not include 4-byte extended timestamp field if present.
369+
if (in.remaining() < headerLength) {
368370
state.bufferDecoding(headerLength - in.remaining());
369371
in.position(startPostion);
370372
return null;
371-
} else {
372-
int currentPostition = in.position();
373-
// medium int is 3 bytes
374-
int timeBase = RTMPUtils.readUnsignedMediumInt(in);
375-
in.position(currentPostition);
376-
if (timeBase >= MEDIUM_INT_MAX) {
377-
headerLength += 4;
378-
if (in.remaining() < headerLength) {
379-
state.bufferDecoding(headerLength - in.remaining());
380-
in.position(startPostion);
381-
return null;
382-
}
383-
}
384373
}
374+
385375
Header lastHeader = rtmp.getLastReadHeader(channelId);
386376
if (log.isTraceEnabled()) {
387377
log.trace("{} lastHeader: {}", Header.HeaderType.values()[headerSize], lastHeader);
@@ -403,11 +393,7 @@ public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in,
403393
// if (log.isTraceEnabled()) {
404394
// log.trace("headerLength: {}", headerLength);
405395
// }
406-
if (in.remaining() < headerLength) {
407-
//log.trace("Header too small (hlen: {}), buffering. remaining: {}", headerLength, remaining);
408-
state.bufferDecoding(headerLength);
409-
return null;
410-
}
396+
411397
int timeBase = 0, timeDelta = 0;
412398
Header header = new Header();
413399
header.setChannelId(channelId);
@@ -420,6 +406,12 @@ public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in,
420406
header.setStreamId(RTMPUtils.readReverseInt(in));
421407
// read the extended timestamp if we have the indication that it exists
422408
if (timeBase >= MEDIUM_INT_MAX) {
409+
headerLength += 4;
410+
if (in.remaining() < 4) {
411+
state.bufferDecoding(headerLength - in.remaining());
412+
in.position(startPostion);
413+
return null;
414+
}
423415
long ext = in.getUnsignedInt();
424416
timeBase = (int) (ext ^ (ext >>> 32));
425417
if (log.isTraceEnabled()) {
@@ -440,6 +432,12 @@ public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in,
440432
header.setStreamId(lastHeader.getStreamId());
441433
// read the extended timestamp if we have the indication that it exists
442434
if (timeDelta >= MEDIUM_INT_MAX) {
435+
headerLength += 4;
436+
if (in.remaining() < 4) {
437+
state.bufferDecoding(headerLength - in.remaining());
438+
in.position(startPostion);
439+
return null;
440+
}
443441
long ext = in.getUnsignedInt();
444442
timeDelta = (int) (ext ^ (ext >>> 32));
445443
header.setExtended(true);
@@ -457,6 +455,12 @@ public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in,
457455
header.setStreamId(lastHeader.getStreamId());
458456
// read the extended timestamp if we have the indication that it exists
459457
if (timeDelta >= MEDIUM_INT_MAX) {
458+
headerLength += 4;
459+
if (in.remaining() < 4) {
460+
state.bufferDecoding(headerLength - in.remaining());
461+
in.position(startPostion);
462+
return null;
463+
}
460464
long ext = in.getUnsignedInt();
461465
timeDelta = (int) (ext ^ (ext >>> 32));
462466
header.setExtended(true);
@@ -475,6 +479,12 @@ public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in,
475479
// This field is present in Type 3 chunks when the most recent Type 0, 1, or 2 chunk for the same chunk stream ID
476480
// indicated the presence of an extended timestamp field
477481
if (lastHeader.isExtended()) {
482+
headerLength += 4;
483+
if (in.remaining() < 4) {
484+
state.bufferDecoding(headerLength - in.remaining());
485+
in.position(startPostion);
486+
return null;
487+
}
478488
long ext = in.getUnsignedInt();
479489
int timeExt = (int) (ext ^ (ext >>> 32));
480490
if (log.isTraceEnabled()) {

0 commit comments

Comments
 (0)