diff --git a/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java b/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java index a102235e3cbbe15b3dab7c6cac39042c656be25f..8608c1587796a111d08ca6a6028eab802bf401af 100644 --- a/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java +++ b/common/src/main/java/org/red5/server/net/rtmp/codec/RTMPProtocolDecoder.java @@ -226,31 +226,16 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder { RTMP rtmp = conn.getState(); // read the chunk header (variable from 1-3 bytes) final ChunkHeader chunkHeader = ChunkHeader.read(in); - // represents "packet" header length via "format" only 1 byte in the chunk header is needed here - int headerLength = RTMPUtils.getHeaderLength(chunkHeader.getFormat()); - headerLength += chunkHeader.getSize() - 1; - if (in.remaining() < headerLength || in.remaining() < 3) { - state.bufferDecoding(headerLength - in.remaining()); - in.position(position); + final Header header = decodeHeader(chunkHeader, state, in, rtmp, position); + // header is null if we were unable to decode it, we may just need more data + if (header == null) { + // we were unable to decode the header, return null return null; - } else { - int currentPostition = in.position(); - // medium int is 3 bytes - int timeBase = RTMPUtils.readUnsignedMediumInt(in); - in.position(currentPostition); - if (timeBase >= MEDIUM_INT_MAX) { - headerLength += 4; - if (in.remaining() < headerLength) { - state.bufferDecoding(headerLength - in.remaining()); - in.position(position); - return null; - } - } } - final Header header = decodeHeader(chunkHeader, state, in, rtmp); // get the channel id final int channelId = header != null ? header.getChannelId() : chunkHeader.getChannelId(); - if (header == null || header.isEmpty()) { + // header empty vs header null will return the NS_FAILED message + if (header.isEmpty()) { if (log.isTraceEnabled()) { log.trace("Header was null or empty - chh: {}", chunkHeader); } @@ -366,7 +351,7 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder { * RTMP object to get last header * @return Decoded header */ - public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in, RTMP rtmp) { + public Header decodeHeader(ChunkHeader chh, RTMPDecodeState state, IoBuffer in, RTMP rtmp, int startPostion) { //if (log.isTraceEnabled()) { //log.trace("decodeHeader - chh: {} input: {}", chh, Hex.encodeHexString(Arrays.copyOfRange(in.array(), in.position(), in.limit()))); //log.trace("decodeHeader - chh: {}", chh); @@ -374,6 +359,27 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder { final int channelId = chh.getChannelId(); // identifies the header type of the four types final byte headerSize = chh.getFormat(); + // represents "packet" header length via "format" only 1 byte in the chunk header is needed here + int headerLength = RTMPUtils.getHeaderLength(headerSize); + headerLength += chh.getSize() - 1; + if (in.remaining() < headerLength || in.remaining() < 3) { + state.bufferDecoding(headerLength - in.remaining()); + in.position(startPostion); + return null; + } else { + int currentPostition = in.position(); + // medium int is 3 bytes + int timeBase = RTMPUtils.readUnsignedMediumInt(in); + in.position(currentPostition); + if (timeBase >= MEDIUM_INT_MAX) { + headerLength += 4; + if (in.remaining() < headerLength) { + state.bufferDecoding(headerLength - in.remaining()); + in.position(startPostion); + return null; + } + } + } Header lastHeader = rtmp.getLastReadHeader(channelId); if (log.isTraceEnabled()) { log.trace("{} lastHeader: {}", Header.HeaderType.values()[headerSize], lastHeader); @@ -392,8 +398,6 @@ public class RTMPProtocolDecoder implements Constants, IEventDecoder { return null; } } - int headerLength = RTMPUtils.getHeaderLength(headerSize); - headerLength += chh.getSize() - 1; // if (log.isTraceEnabled()) { // log.trace("headerLength: {}", headerLength); // }