bool Header::Write(Channel &channel, IOBuffer &buffer) { //1. Compute the header size if (channel.lastOutStreamId == H_SI(*this)) { if (H_IA(*this)) { if (channel.lastOutProcBytes == 0) { H_HT(*this) = HT_FULL; channel.lastOutAbsTs = H_TS(*this); } else { H_HT(*this) = HT_CONTINUATION; } } else { if (channel.lastOutProcBytes == 0) { H_HT(*this) = HT_SAME_STREAM; if ((H_MT(*this) == H_MT(channel.lastOutHeader)) && (H_ML(*this) == H_ML(channel.lastOutHeader))) { H_HT(*this) = HT_SAME_LENGTH_AND_STREAM; if (H_TS(*this) == H_TS(channel.lastOutHeader)) { H_HT(*this) = HT_CONTINUATION; } } channel.lastOutAbsTs += H_TS(*this); } else { H_HT(*this) = HT_CONTINUATION; } } } else { H_HT(*this) = HT_FULL; H_IA(*this) = true; channel.lastOutAbsTs = H_TS(*this); channel.lastOutStreamId = H_SI(*this); } #ifdef ENFORCE_RTMP_OUTPUT_CHECKS switch (ht) { case HT_FULL: { o_assert(channel.lastOutProcBytes == 0); o_assert(H_IA(*this)); break; } case HT_SAME_STREAM: { o_assert(channel.lastOutProcBytes == 0); o_assert(channel.lastOutStreamId == hf.s.si); o_assert(channel.lastOutStreamId == channel.lastOutHeader.hf.s.si); break; } case HT_SAME_LENGTH_AND_STREAM: { o_assert(channel.lastOutProcBytes == 0); o_assert(channel.lastOutStreamId == hf.s.si); o_assert(channel.lastOutStreamId == channel.lastOutHeader.hf.s.si); o_assert(channel.lastOutHeader.hf.s.mt == hf.s.mt); o_assert(channel.lastOutHeader.hf.s.ml == hf.s.ml); o_assert(channel.lastOutHeader.hf.s.ts != hf.s.ts); break; } case HT_CONTINUATION: { o_assert(channel.lastOutStreamId == hf.s.si); o_assert(channel.lastOutStreamId == channel.lastOutHeader.hf.s.si); o_assert(channel.lastOutHeader.hf.s.mt == hf.s.mt); o_assert(channel.lastOutHeader.hf.s.ml == hf.s.ml); o_assert(channel.lastOutHeader.hf.s.ts == hf.s.ts); break; } default: { ASSERT("Invalid header type!!!"); } } #endif /* ENFORCE_RTMP_OUTPUT_CHECKS */ //2. Save the last sent header channel.lastOutHeader = *this; //3. do the write return Write(buffer); }
bool RTMPProtocolSerializer::Deserialize(Header &header, IOBuffer &buffer, Variant &message) { message.Reset(); message[RM_HEADER] = header.GetVariant(); switch (H_MT(header)) { case RM_HEADER_MESSAGETYPE_NOTIFY: { return DeserializeNotify(buffer, message[RM_NOTIFY]); } case RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: { return DeserializeFlexStreamSend(buffer, message[RM_FLEXSTREAMSEND]); } case RM_HEADER_MESSAGETYPE_INVOKE: case RM_HEADER_MESSAGETYPE_FLEX: { message[RM_INVOKE][RM_INVOKE_IS_FLEX] = (bool)(H_MT(header) == RM_HEADER_MESSAGETYPE_FLEX); return DeserializeInvoke(buffer, message[RM_INVOKE]); } case RM_HEADER_MESSAGETYPE_FLEXSHAREDOBJECT: { //TODO: This is a hack. We store the data on RM_SHAREDOBJECT //instead of RM_FLEXSHAREDOBJECT //return DeserializeFlexSharedObject(buffer, message[RM_FLEXSHAREDOBJECT]); return DeserializeFlexSharedObject(buffer, message[RM_SHAREDOBJECT]); } case RM_HEADER_MESSAGETYPE_SHAREDOBJECT: { return DeserializeSharedObject(buffer, message[RM_SHAREDOBJECT]); } case RM_HEADER_MESSAGETYPE_USRCTRL: { return DeserializeUsrCtrl(buffer, message[RM_USRCTRL]); } case RM_HEADER_MESSAGETYPE_CHUNKSIZE: { return DeserializeChunkSize(buffer, message[RM_CHUNKSIZE]); } case RM_HEADER_MESSAGETYPE_ACK: { return DeserializeAck(buffer, message[RM_ACK]); } case RM_HEADER_MESSAGETYPE_WINACKSIZE: { return DeserializeWinAckSize(buffer, message[RM_WINACKSIZE]); } case RM_HEADER_MESSAGETYPE_PEERBW: { return DeserializePeerBW(buffer, message[RM_PEERBW]); } case RM_HEADER_MESSAGETYPE_ABORTMESSAGE: { return DeserializeAbortMessage(buffer, message[RM_ABORTMESSAGE]); } default: { FATAL("Invalid message type: %u %s", H_MT(header), STR(buffer)); return false; } } }
bool MonitorRTMPProtocol::ProcessBytes(IOBuffer &buffer) { while (true) { uint32_t availableBytesCount = GETAVAILABLEBYTESCOUNT(buffer); if (_selectedChannel < 0) { if (availableBytesCount < 1) { return true; } else { switch (GETIBPOINTER(buffer)[0]&0x3f) { case 0: { if (availableBytesCount < 2) { FINEST("Not enough data"); return true; } _selectedChannel = 64 + GETIBPOINTER(buffer)[1]; _channels[_selectedChannel].lastInHeaderType = GETIBPOINTER(buffer)[0] >> 6; buffer.Ignore(2); availableBytesCount -= 2; break; } case 1: { // if (availableBytesCount < 3) { // FINEST("Not enough data"); // return true; // } // _selectedChannel = GETIBPOINTER(buffer)[2]*256 + GETIBPOINTER(buffer)[1] + 64; // _channels[_selectedChannel].lastInHeaderType = GETIBPOINTER(buffer)[0] >> 6; // buffer.Ignore(3); // availableBytesCount -= 3; // break; FATAL("The server doesn't support channel ids bigger than 319"); return false; }; default: { _selectedChannel = GETIBPOINTER(buffer)[0]&0x3f; _channels[_selectedChannel].lastInHeaderType = GETIBPOINTER(buffer)[0] >> 6; buffer.Ignore(1); availableBytesCount -= 1; break; } } } } Channel &channel = _channels[_selectedChannel]; Header &header = channel.lastInHeader; FINEST("header: %s", STR(header)); if (channel.state == CS_HEADER) { if (!header.Read(_selectedChannel, channel.lastInHeaderType, buffer, availableBytesCount)) { FATAL("Unable to read header"); return false; } else { if (!header.readCompleted) return true; if (H_SI(header) >= _maxStreamCount) { FATAL("%s", STR(header)); FATAL("buffer:\n%s", STR(buffer)); ASSERT("invalid stream index"); } if (H_CI(header) >= _maxChannelsCount) { FATAL("%s", STR(header)); FATAL("buffer:\n%s", STR(buffer)); ASSERT("invalid channel index"); } switch ((uint8_t) H_MT(header)) { case RM_HEADER_MESSAGETYPE_ABORTMESSAGE: case RM_HEADER_MESSAGETYPE_ACK: case RM_HEADER_MESSAGETYPE_AGGREGATE: case RM_HEADER_MESSAGETYPE_AUDIODATA: case RM_HEADER_MESSAGETYPE_CHUNKSIZE: case RM_HEADER_MESSAGETYPE_FLEX: case RM_HEADER_MESSAGETYPE_FLEXSHAREDOBJECT: case RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: case RM_HEADER_MESSAGETYPE_INVOKE: case RM_HEADER_MESSAGETYPE_NOTIFY: case RM_HEADER_MESSAGETYPE_PEERBW: case RM_HEADER_MESSAGETYPE_SHAREDOBJECT: case RM_HEADER_MESSAGETYPE_USRCTRL: case RM_HEADER_MESSAGETYPE_VIDEODATA: case RM_HEADER_MESSAGETYPE_WINACKSIZE: { break; } default: { FATAL("%s", STR(header)); FATAL("buffer:\n%s", STR(buffer)); ASSERT("invalid message type"); } } channel.state = CS_PAYLOAD; switch (channel.lastInHeaderType) { case HT_FULL: { channel.lastInAbsTs = H_TS(header); break; } case HT_SAME_STREAM: case HT_SAME_LENGTH_AND_STREAM: { channel.lastInAbsTs += H_TS(header); break; } case HT_CONTINUATION: { if (channel.lastInProcBytes == 0) { channel.lastInAbsTs += H_TS(header); } break; } } } } if (channel.state == CS_PAYLOAD) { uint32_t tempSize = H_ML(header) - channel.lastInProcBytes; tempSize = (tempSize >= _inboundChunkSize) ? _inboundChunkSize : tempSize; uint32_t availableBytes = GETAVAILABLEBYTESCOUNT(buffer); if (tempSize > availableBytes) return true; channel.state = CS_HEADER; _selectedChannel = -1; switch (H_MT(header)) { case RM_HEADER_MESSAGETYPE_VIDEODATA: { if (H_SI(header) >= _maxStreamCount) { FATAL("Incorrect stream index"); return false; } //FINEST("Video data"); channel.lastInProcBytes += tempSize; if (H_ML(header) == channel.lastInProcBytes) { channel.lastInProcBytes = 0; } if (!buffer.Ignore(tempSize)) { FATAL("V: Unable to ignore %u bytes", tempSize); return false; } break; } case RM_HEADER_MESSAGETYPE_AUDIODATA: { if (H_SI(header) >= _maxStreamCount) { FATAL("Incorrect stream index"); return false; } //FINEST("Audio data"); channel.lastInProcBytes += tempSize; if (H_ML(header) == channel.lastInProcBytes) { channel.lastInProcBytes = 0; } if (!buffer.Ignore(tempSize)) { FATAL("A: Unable to ignore %u bytes", tempSize); return false; } break; } default: { channel.inputData.ReadFromInputBuffer(buffer, tempSize); channel.lastInProcBytes += tempSize; if (!buffer.Ignore(tempSize)) { FATAL("Unable to ignore %u bytes", tempSize); return false; } if (H_ML(header) == channel.lastInProcBytes) { channel.lastInProcBytes = 0; Variant msg; if (!_rtmpProtocolSerializer.Deserialize(header, channel.inputData, msg)) { FATAL("Unable to deserialize message"); return false; } if ((uint8_t) VH_MT(msg) == RM_HEADER_MESSAGETYPE_CHUNKSIZE) { _inboundChunkSize = (uint32_t) msg[RM_CHUNKSIZE]; } if ((uint8_t) VH_MT(msg) == RM_HEADER_MESSAGETYPE_ABORTMESSAGE) { uint32_t channelId = (uint32_t) msg[RM_ABORTMESSAGE]; if (channelId >= _maxChannelsCount) { FATAL("Invalid channel id in reset message: %" PRIu32, channelId); return false; } o_assert(_channels[channelId].id == channelId); _channels[channelId].Reset(); } if (GETAVAILABLEBYTESCOUNT(channel.inputData) != 0) { FATAL("Invalid message! We have leftovers: %u bytes", GETAVAILABLEBYTESCOUNT(channel.inputData)); return false; } } break; } } } } }