bool AMF0Serializer::ReadLongString(IOBuffer &buffer, Variant &variant, bool readType) { if (readType) { AMF_CHECK_BOUNDARIES(buffer, 1); if (GETIBPOINTER(buffer)[0] != AMF0_LONG_STRING) { FATAL("AMF type not valid: want: %"PRIu8"; got: %"PRIu8, AMF0_LONG_STRING, GETIBPOINTER(buffer)[0]); return false; } if (!buffer.Ignore(1)) { FATAL("Unable to ignore 1 bytes"); return false; } } AMF_CHECK_BOUNDARIES(buffer, 4); uint32_t length = ENTOHLP(GETIBPOINTER(buffer)); //----MARKED-LONG--- if (!buffer.Ignore(4)) { FATAL("Unable to ignore 4 bytes"); return false; } AMF_CHECK_BOUNDARIES(buffer, length); variant = string((char *) (GETIBPOINTER(buffer)), length); if (!buffer.Ignore(length)) { FATAL("Unable to ignore %"PRIu32" bytes", length); return false; } return true; }
bool AMF0Serializer::ReadShortString(IOBuffer &buffer, Variant &variant, bool readType) { if (readType) { AMF_CHECK_BOUNDARIES(buffer, 1); if (GETIBPOINTER(buffer)[0] != AMF0_SHORT_STRING) { FATAL("AMF type not valid: want: %hhu; got: %hhu", AMF0_SHORT_STRING, GETIBPOINTER(buffer)[0]); return false; } if (!buffer.Ignore(1)) { FATAL("Unable to ignore 1 bytes"); return false; } } AMF_CHECK_BOUNDARIES(buffer, 2); uint16_t length = ENTOHSP(GETIBPOINTER(buffer)); //----MARKED-SHORT---- if (!buffer.Ignore(2)) { FATAL("Unable to ignore 2 bytes"); return false; } AMF_CHECK_BOUNDARIES(buffer, length); variant = string((char *) (GETIBPOINTER(buffer)), length); if (!buffer.Ignore(length)) { FATAL("Unable to ignore %hu bytes", length); return false; } return true; }
bool AMF0Serializer::ReadDouble(IOBuffer &buffer, Variant &variant, bool readType) { if (readType) { AMF_CHECK_BOUNDARIES(buffer, 1); if (GETIBPOINTER(buffer)[0] != AMF0_NUMBER) { FATAL("AMF type not valid: want: %hhu; got: %hhu", AMF0_NUMBER, GETIBPOINTER(buffer)[0]); return false; } if (!buffer.Ignore(1)) { FATAL("Unable to ignore 1 bytes"); return false; } } AMF_CHECK_BOUNDARIES(buffer, 8); double temp = 0; ENTOHDP(GETIBPOINTER(buffer), temp); variant = (double) temp; if (!buffer.Ignore(8)) { FATAL("Unable to ignore 8 bytes"); return false; } return true; }
bool InboundJSONCLIProtocol::SignalInputData(IOBuffer &buffer) { //1. Get the buffer and the length uint8_t *pBuffer = GETIBPOINTER(buffer); uint32_t length = GETAVAILABLEBYTESCOUNT(buffer); if (length == 0) return true; //2. Walk through the buffer and execute the commands string command = ""; for (uint32_t i = 0; i < length; i++) { if ((pBuffer[i] == 0x0d) || (pBuffer[i] == 0x0a)) { if (command != "") { if (!ParseCommand(command)) { FATAL("Unable to parse command\n`%s`", STR(command)); return false; } } command = ""; buffer.Ignore(i); pBuffer = GETIBPOINTER(buffer); length = GETAVAILABLEBYTESCOUNT(buffer); i = 0; continue; } command += (char) pBuffer[i]; if (command.length() >= MAX_COMMAND_LENGTH) { FATAL("Command too long"); return false; } } //3. Done return true; }
bool BaseVariantProtocol::SignalInputData(IOBuffer &buffer) { if (_pProtocolHandler == NULL) { FATAL("This protocol is not registered to any application yet"); return false; } if (_pFarProtocol->GetType() == PT_OUTBOUND_HTTP || _pFarProtocol->GetType() == PT_INBOUND_HTTP) { #ifdef HAS_PROTOCOL_HTTP //1. This is a HTTP based transfer. We only start doing stuff //after a complete request is made. BaseHTTPProtocol *pHTTPProtocol = (BaseHTTPProtocol *) _pFarProtocol; if (!pHTTPProtocol->TransferCompleted()) return true; if (!Deserialize(GETIBPOINTER(buffer), pHTTPProtocol->GetContentLength(), _lastReceived)) { FATAL("Unable to deserialize content"); return false; } buffer.Ignore(pHTTPProtocol->GetContentLength()); _lastReceived.Compact(); return _pProtocolHandler->ProcessMessage(this, _lastSent, _lastReceived); #else FATAL("HTTP protocol not supported"); return false; #endif /* HAS_PROTOCOL_HTTP */ } else if (_pFarProtocol->GetType() == PT_TCP) { while (GETAVAILABLEBYTESCOUNT(buffer) > 4) { uint32_t size = ENTOHLP(GETIBPOINTER(buffer)); if (size > 4 * 1024 * 1024) { FATAL("Size too big: %u", size); return false; } if (GETAVAILABLEBYTESCOUNT(buffer) < size + 4) { FINEST("Need more data"); return true; } if (!Deserialize(GETIBPOINTER(buffer) + 4, size, _lastReceived)) { FATAL("Unable to deserialize variant"); return false; } buffer.Ignore(size + 4); _lastReceived.Compact(); if (!_pProtocolHandler->ProcessMessage(this, _lastSent, _lastReceived)) { FATAL("Unable to process message"); return false; } } return true; } else { FATAL("Invalid protocol stack"); return false; } }
bool InboundRTMPProtocol::ValidateClientScheme(IOBuffer &inputBuffer, uint8_t scheme) { uint8_t *pBuffer = GETIBPOINTER(inputBuffer); uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, pBuffer, clientDigestOffset); memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 1536 - clientDigestOffset - 32); uint8_t *pTempHash = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); bool result = true; for (uint32_t i = 0; i < 32; i++) { if (pBuffer[clientDigestOffset + i] != pTempHash[i]) { result = false; break; } } delete[] pTempBuffer; delete[] pTempHash; return result; }
bool HTTP4CLIProtocol::EnqueueForOutbound() { //1. Empty our local buffer _localOutputBuffer.IgnoreAll(); //2. Get the HTTP protocol InboundHTTPProtocol *pHTTP = (InboundHTTPProtocol *) GetFarProtocol(); //3. Prepare the HTTP headers //pHTTP->SetOutboundHeader(HTTP_HEADERS_CONTENT_TYPE, "application/json"); pHTTP->SetOutboundHeader(HTTP_HEADERS_CONTENT_TYPE, "text/plain"); //4. Get the buffer from PT_INBOUND_JSONCLI IOBuffer *pBuffer = GetNearProtocol()->GetOutputBuffer(); if (pBuffer == NULL) return true; //5. Put the data inside the local buffer and empty the buffer from //the PT_INBOUND_JSONCLI _localOutputBuffer.ReadFromBuffer(GETIBPOINTER(*pBuffer), GETAVAILABLEBYTESCOUNT(*pBuffer)); pBuffer->IgnoreAll(); //6. Trigger EnqueueForOutbound down the stack return pHTTP->EnqueueForOutbound(); }
bool BaseHTTPProtocol::HandleFixedLengthContent(IOBuffer &buffer) { //1. Compute the chunk size that we areg going to read //which is how many bytes we have available, but no more than _contentLength uint32_t chunkSize = GETAVAILABLEBYTESCOUNT(buffer); o_assert(_sessionDecodedBytesCount <= _contentLength); uint32_t remaining = _contentLength - _sessionDecodedBytesCount; chunkSize = chunkSize > remaining ? remaining : chunkSize; //2. Update the session decoded bytes count and decoded bytes count _sessionDecodedBytesCount += chunkSize; _decodedBytesCount += chunkSize; //3. Make the copy and ignore the chunk size _inputBuffer.ReadFromBuffer(GETIBPOINTER(buffer), chunkSize); buffer.Ignore(chunkSize); //3. Call the near protocol if (!_pNearProtocol->SignalInputData(_inputBuffer)) { FATAL("Unable to call the next protocol in stack"); return false; } //4. reset the state if necessary if (TransferCompleted()) { _headers.Reset(); _contentLength = 0; _chunkedContent = false; _lastChunk = false; _state = HTTP_STATE_HEADERS; _sessionDecodedBytesCount = 0; } //5. we are done return true; }
void AtomMDAT::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) { uint32_t start=GETAVAILABLEBYTESCOUNT(data); BaseAtom::SerializeToBuffer(data, maxFrames); _size=GETAVAILABLEBYTESCOUNT(data)-start; *(uint32_t*)(GETIBPOINTER(data)+start) = endianSwap32(_size); }
void AtomURL::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) { uint32_t start=GETAVAILABLEBYTESCOUNT(data); VersionedAtom::SerializeToBuffer(data, maxFrames); data.ReadFromString(_location); _size=GETAVAILABLEBYTESCOUNT(data)-start; *(uint32_t*)(GETIBPOINTER(data)+start) = endianSwap32(_size); }
bool StreamCapabilities::Deserialize(string seekFilePath, StreamCapabilities &capabilities) { File file; if (!file.Initialize(seekFilePath, FILE_OPEN_MODE_READ)) { FATAL("Unable to open seek file %s", STR(seekFilePath)); return false; } uint32_t length = 0; if (!file.ReadUI32(&length, false)) { FATAL("Unable to read stream capabilities length from file %s", STR(seekFilePath)); return false; } if (length > 1024 * 1024) { FATAL("Invalid stream capabilities length in file %s: %"PRIu32, STR(seekFilePath), length); return false; } IOBuffer buffer; buffer.ReadFromRepeat(0, length); if (!file.ReadBuffer(GETIBPOINTER(buffer), length)) { FATAL("Unable to read stream capabilities payload from file %s", STR(seekFilePath)); return false; } file.Close(); if (!Deserialize(buffer, capabilities)) { FATAL("Unable to deserialize stream capabilities from file %s", STR(seekFilePath)); return false; } return true; }
bool BaseMediaDocument::SaveSeekFile() { if (_frames.size() <= 2) { FATAL("No frames found"); return false; } File seekFile; //1. Open the file if (!seekFile.Initialize(_seekFilePath + ".tmp", FILE_OPEN_MODE_TRUNCATE)) { FATAL("Unable to open seeking file %s", STR(_seekFilePath)); return false; } //2. Setup the bandwidth hint in bytes/second uint32_t totalSeconds = (uint32_t) (((uint32_t) _frames[_frames.size() - 1].absoluteTime) / 1000); _streamCapabilities.bandwidthHint = (uint32_t) ((double) _mediaFile.Size() / (double) totalSeconds / 1024.0 * 8.0); //2. Serialize the stream capabilities IOBuffer raw; if (!_streamCapabilities.Serialize(raw)) { FATAL("Unable to serialize stream capabilities"); return false; } if (!seekFile.WriteUI32(GETAVAILABLEBYTESCOUNT(raw), false)) { FATAL("Unable to serialize stream capabilities"); return false; } if (!seekFile.WriteBuffer(GETIBPOINTER(raw), GETAVAILABLEBYTESCOUNT(raw))) { FATAL("Unable to serialize stream capabilities"); return false; } //2. Write the number of frames uint32_t framesCount = (uint32_t) _frames.size(); if (!seekFile.WriteUI32(framesCount, false)) { FATAL("Unable to write frame count"); return false; } //3. Write the frames bool hasVideo = false; uint64_t maxFrameSize = 0; FOR_VECTOR(_frames, i) { MediaFrame &frame = _frames[i]; if (maxFrameSize < frame.length) { //WARN("maxFrameSize bumped up: %"PRIu64" -> %"PRIu64, maxFrameSize, frame.length); maxFrameSize = frame.length; } hasVideo |= (frame.type == MEDIAFRAME_TYPE_VIDEO); if (!seekFile.WriteBuffer((uint8_t *) & frame, sizeof (frame))) { FATAL("Unable to write frame"); return false; } }
bool BaseHTTPProtocol::EnqueueForOutbound() { //1. Get the output buffer if (_pNearProtocol == NULL) { FATAL("No near protocol"); return false; } IOBuffer *pBuffer = _pNearProtocol->GetOutputBuffer(); uint32_t bufferLength = 0; if (pBuffer != NULL) { bufferLength = GETAVAILABLEBYTESCOUNT(*pBuffer); } //3. add or replace X-Powered-By attribute _outboundHeaders[HTTP_HEADERS_X_POWERED_BY] = HTTP_HEADERS_X_POWERED_BY_US; //4. add or replace the Server attribute if (GetType() == PT_INBOUND_HTTP) { _outboundHeaders[HTTP_HEADERS_SERVER] = HTTP_HEADERS_SERVER_US; } //5. Get rid of the Content-Length attribute and add it only if necessary _outboundHeaders.RemoveKey(HTTP_HEADERS_CONTENT_LENGTH); if (bufferLength > 0) { _outboundHeaders[HTTP_HEADERS_CONTENT_LENGTH] = format("%u", bufferLength); } //6. Get rid of Transfer-Encoding attribute _outboundHeaders.RemoveKey(HTTP_HEADERS_TRANSFER_ENCODING); //7. Write the first line of the request/response _outputBuffer.ReadFromString(GetOutputFirstLine() + "\r\n"); //8. Write the headers and the final '\r\n' FOR_MAP(_outboundHeaders, string, Variant, i) { if (MAP_VAL(i) != V_STRING) { FATAL("Invalid HTTP headers:\n%s", STR(_outboundHeaders.ToString())); return false; } _outputBuffer.ReadFromString(format("%s: %s\r\n", STR(MAP_KEY(i)), STR(MAP_VAL(i)))); } _outboundHeaders.Reset(); _outboundHeaders.IsArray(false); _outputBuffer.ReadFromString("\r\n"); //9. Write the actual content if necessary if (bufferLength > 0) { _outputBuffer.ReadFromBuffer(GETIBPOINTER(*pBuffer), GETAVAILABLEBYTESCOUNT(*pBuffer)); //10. Empty the upper output buffer pBuffer->IgnoreAll(); } //11. Let the request flow further return BaseProtocol::EnqueueForOutbound(); }
bool AMF0Serializer::ReadObject(IOBuffer &buffer, Variant &variant, bool readType) { if (readType) { AMF_CHECK_BOUNDARIES(buffer, 1); if (GETIBPOINTER(buffer)[0] != AMF0_OBJECT) { FATAL("AMF type not valid: want: %"PRIu8"; got: %"PRIu8, AMF0_OBJECT, GETIBPOINTER(buffer)[0]); return false; } if (!buffer.Ignore(1)) { FATAL("Unable to ignore 1 bytes"); return false; } } AMF_CHECK_BOUNDARIES(buffer, 3); while (!((GETIBPOINTER(buffer)[0] == 0) && (GETIBPOINTER(buffer)[1] == 0) && (GETIBPOINTER(buffer)[2] == 9))) { Variant key; Variant value; if (!ReadShortString(buffer, key, false)) { FATAL("Unable to read key"); return false; } if (!Read(buffer, value)) { FATAL("Unable to read value"); return false; } variant[key] = value; } AMF_CHECK_BOUNDARIES(buffer, 3); if (!buffer.Ignore(3)) { FATAL("Unable to ignore 3 bytes"); return false; } variant.IsArray(false); return true; }
bool OutboundRTMPProtocol::VerifyServer(IOBuffer & inputBuffer) { uint8_t *pBuffer = GETIBPOINTER(inputBuffer) + 1; uint32_t serverDigestOffset = GetDigestOffset(pBuffer, _usedScheme); DEBUG_HANDSHAKE("CLIENT: Validate: 1. serverDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8, serverDigestOffset, _usedScheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, pBuffer, serverDigestOffset); memcpy(pTempBuffer + serverDigestOffset, pBuffer + serverDigestOffset + 32, 1536 - serverDigestOffset - 32); uint8_t * pDigest = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pDigest); DEBUG_HANDSHAKE("CLIENT: Validate: 2. computed serverDigest %s", STR(hex(pDigest, 32))); DEBUG_HANDSHAKE("CLIENT: Validate: 3. found serverDigest %s", STR(hex(pBuffer + serverDigestOffset, 32))); int result = memcmp(pDigest, pBuffer + serverDigestOffset, 32); delete[] pTempBuffer; delete[] pDigest; if (result != 0) { FATAL("Server not verified"); return false; } pBuffer = pBuffer + 1536; uint8_t * pChallange = new uint8_t[512]; HMACsha256(_pClientDigest, 32, genuineFMSKey, 68, pChallange); pDigest = new uint8_t[512]; HMACsha256(pBuffer, 1536 - 32, pChallange, 32, pDigest); DEBUG_HANDSHAKE("CLIENT: Validate: 4. computed serverChallange: %s", STR(hex(pDigest, 32))); DEBUG_HANDSHAKE("CLIENT: Validate: 5. found serverChallange: %s", STR(hex(pBuffer + 1536 - 32, 32))); result = memcmp(pDigest, pBuffer + 1536 - 32, 32); delete[] pChallange; delete[] pDigest; if (result != 0) { FATAL("Server not verified"); return false; } return true; }
bool BaseSSLProtocol::SignalInputData(IOBuffer &buffer) { //1. get the SSL input buffer BIO *pInBio = SSL_get_rbio(_pSSL); //2. dump all the data from the network inside the ssl input BIO_write(pInBio, GETIBPOINTER(buffer), GETAVAILABLEBYTESCOUNT(buffer)); buffer.IgnoreAll(); //3. Do we have to do some handshake? if (!_sslHandshakeCompleted) { if (!DoHandshake()) { FATAL("Unable to do the SSL handshake"); return false; } if (!_sslHandshakeCompleted) { return true; } } //4. Read the actual data an put it in the descrypted input buffer int32_t read = 0; while ((read = SSL_read(_pSSL, _pReadBuffer, MAX_SSL_READ_BUFFER)) > 0) { _inputBuffer.ReadFromBuffer(_pReadBuffer, (uint32_t) read); } if (read < 0) { int32_t error = SSL_get_error(_pSSL, read); if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE) { FATAL("Unable to read data: %d", error); return false; } } //6. If we have pending data inside the decrypted buffer, bubble it up on the protocol stack if (GETAVAILABLEBYTESCOUNT(_inputBuffer) > 0) { if (_pNearProtocol != NULL) { if (!_pNearProtocol->SignalInputData(_inputBuffer)) { FATAL("Unable to signal near protocol for new data"); return false; } } } //7. After the data was sent on the upper layers, we might have outstanding //data that needs to be sent. return PerformIO(); }
bool StreamCapabilities::Deserialize(IOBuffer &src, StreamCapabilities &capabilities) { uint8_t *pBuffer = GETIBPOINTER(src); uint32_t length = GETAVAILABLEBYTESCOUNT(src); if (length < 28) { FATAL("Not enough data"); return false; } uint64_t ver = ENTOHLLP(pBuffer); if (ver != __STREAM_CAPABILITIES_VERSION) { FATAL("Invalid stream capabilities version. Wanted: %"PRIu64"; Got: %"PRIu64, __STREAM_CAPABILITIES_VERSION, ver); return false; } capabilities.Clear(); capabilities.videoCodecId = ENTOHLLP(pBuffer + 8); capabilities.audioCodecId = ENTOHLLP(pBuffer + 16); capabilities.bandwidthHint = ENTOHLP(pBuffer + 24); src.Ignore(28); switch (capabilities.videoCodecId) { case CODEC_VIDEO_AVC: { if (!_VIDEO_AVC::Deserialize(src, capabilities.avc)) { FATAL("Unable to deserialize avc"); return false; } break; } default: { break; } } switch (capabilities.audioCodecId) { case CODEC_AUDIO_AAC: { if (!_AUDIO_AAC::Deserialize(src, capabilities.aac)) { FATAL("Unable to deserialize aac"); return false; } break; } default: { break; } } return true; }
bool InboundHTTP4RTMP::ProcessIdle(vector<string> &parts) { BaseProtocol *pProtocol = Bind(parts[2]); if (pProtocol == NULL) { FATAL("Unable to bind protocol"); return false; } _outputBuffer.ReadFromByte(1); IOBuffer *pBuffer = pProtocol->GetOutputBuffer(); if (pBuffer != NULL) { _outputBuffer.ReadFromBuffer(GETIBPOINTER(*pBuffer), GETAVAILABLEBYTESCOUNT(*pBuffer)); pBuffer->IgnoreAll(); } return BaseProtocol::EnqueueForOutbound(); }
bool VariantConnection::SendMessage(Variant &message, Variant &response) { string rawContent = " "; if (!message.SerializeToBin(rawContent)) { FATAL("Unable to serialize message"); return false; } uint8_t *pBuffer = (uint8_t *) rawContent.c_str(); uint32_t size = rawContent.size(); EHTONLP(pBuffer, size - 4); int32_t totalSentAmount = 0; int32_t sentAmount = 0; while (totalSentAmount < (int32_t) size) { sentAmount = send(_fd, pBuffer + totalSentAmount, size - totalSentAmount, 0); if (sentAmount <= 0) { return false; } totalSentAmount += sentAmount; } _buffer.IgnoreAll(); int32_t recvAmount = 0; for (;;) { if (!_buffer.ReadFromTCPFd(_fd, 1024 * 1024, recvAmount)) { FATAL("Unable to read from socket"); return false; } size = GETAVAILABLEBYTESCOUNT(_buffer); pBuffer = GETIBPOINTER(_buffer); if (size < 4) { WARN("not enough data. Wait for more..."); continue; } uint32_t variantSize = ENTOHLP(pBuffer); if (variantSize + 4 > size) { WARN("not enough data. Wait for more..."); continue; } if (!Variant::DeserializeFromBin(pBuffer + 4, variantSize, response)) { FATAL("Unable to deserialize buffer"); return false; } return true; } }
bool _AUDIO_AAC::Deserialize(IOBuffer &src, _AUDIO_AAC &dest) { dest.Clear(); uint8_t *pBuffer = GETIBPOINTER(src); uint32_t length = GETAVAILABLEBYTESCOUNT(src); if (length<sizeof (dest._aacLength)) { FATAL("Not enough data"); return false; } dest._aacLength = ENTOHLP(pBuffer); if (length<sizeof (dest._aacLength) + dest._aacLength) { FATAL("Not enough data"); return false; } if (!dest.Init(pBuffer + sizeof (dest._aacLength), dest._aacLength)) { FATAL("Unable to init AAC"); return false; } return src.Ignore(sizeof (dest._aacLength) + dest._aacLength); }
bool InboundRTMPSDiscriminatorProtocol::SignalInputData(IOBuffer &buffer) { //1. Do we have enough data? if (GETAVAILABLEBYTESCOUNT(buffer) < 4) return true; //2. Get the first 4 bytes in a string string method = string((char *) GETIBPOINTER(buffer), 4); //3. Create the proper RTMP stack if (method == HTTP_METHOD_POST) { #ifdef HAS_PROTOCOL_HTTP return BindHTTP(buffer); #else FATAL("No HTTP protocol support"); return false; #endif /* HAS_PROTOCOL_HTTP */ } else { return BindSSL(buffer); } }
void AtomMVHD::SerializeToBuffer(IOBuffer& data, uint32_t maxFrames) { uint32_t start=GETAVAILABLEBYTESCOUNT(data); VersionedAtom::SerializeToBuffer(data, maxFrames); data.ReadFromDataType<uint32_t>(endianSwap32(_creationTime)); data.ReadFromDataType<uint32_t>(endianSwap32(_modificationTime)); data.ReadFromDataType<uint32_t>(endianSwap32(_timeScale)); _offset=GETAVAILABLEBYTESCOUNT(data); data.ReadFromDataType<uint32_t>(endianSwap32(_duration)); data.ReadFromDataType<uint32_t>(endianSwap32(_preferredRate)); data.ReadFromDataType<uint16_t>(endianSwap16(_preferredVolume)); data.ReadFromBuffer(_reserved, sizeof(_reserved)); for (uint32_t i=0; i<9; i++) data.ReadFromDataType<uint32_t>(endianSwap32(_matrixStructure[i])); for (uint32_t i=0; i<6; i++) { data.ReadFromRepeat(0x00, 4); } data.ReadFromDataType<uint32_t>(endianSwap32(_nextTrakId)); _size=GETAVAILABLEBYTESCOUNT(data)-start; *(uint32_t*)(GETIBPOINTER(data)+start) = endianSwap32(_size); }
bool BaseSSLProtocol::EnqueueForOutbound() { //1. Is the SSL handshake completed? if (!_sslHandshakeCompleted) { return DoHandshake(); } //2. Do we have some outstanding data? IOBuffer *pBuffer = _pNearProtocol->GetOutputBuffer(); if (pBuffer == NULL) return true; //3. Encrypt the outstanding data if (SSL_write(_pSSL, GETIBPOINTER(*pBuffer), GETAVAILABLEBYTESCOUNT(*pBuffer)) != (int32_t) GETAVAILABLEBYTESCOUNT(*pBuffer)) { FATAL("Unable to write %u bytes", GETAVAILABLEBYTESCOUNT(*pBuffer)); return false; } pBuffer->IgnoreAll(); //4. Do the actual I/O return PerformIO(); }
bool InboundRTMPProtocol::PerformSimpleHandshake(IOBuffer &buffer) { if (_pOutputBuffer == NULL) { _pOutputBuffer = new uint8_t[1536]; } else { delete[] _pOutputBuffer; _pOutputBuffer = new uint8_t[1536]; } for (uint32_t i = 0; i < 1536; i++) { _pOutputBuffer[i] = rand() % 256; } for (uint32_t i = 0; i < 10; i++) { uint32_t index = (rand() + 8) % (1536 - HTTP_HEADERS_SERVER_US_LEN); memcpy(_pOutputBuffer + index, HTTP_HEADERS_SERVER_US, HTTP_HEADERS_SERVER_US_LEN); } _outputBuffer.ReadFromByte(3); _outputBuffer.ReadFromBuffer(_pOutputBuffer, 1536); _outputBuffer.ReadFromBuffer(GETIBPOINTER(buffer), 1536); //final cleanup delete[] _pOutputBuffer; _pOutputBuffer = NULL; if (!buffer.Ignore(1536)) { FATAL("Unable to ignore input buffer"); return false; } //signal outbound data if (!EnqueueForOutbound()) { FATAL("Unable to signal outbound data"); return false; } //move to the next stage in the handshake _rtmpState = RTMP_STATE_SERVER_RESPONSE_SENT; return true; }
bool _VIDEO_AVC::Deserialize(IOBuffer &src, _VIDEO_AVC &dest) { dest.Clear(); uint8_t *pBuffer = GETIBPOINTER(src); uint32_t length = GETAVAILABLEBYTESCOUNT(src); if (length<sizeof (dest._spsLength)) { FATAL("Not enough data"); return false; } dest._spsLength = ENTOHSP(pBuffer); if (length < ( sizeof (dest._spsLength) + dest._spsLength + sizeof (dest._ppsLength) + 2 * sizeof (uint32_t))) { FATAL("Not enough data"); return false; } dest._ppsLength = ENTOHSP(pBuffer + sizeof (dest._spsLength) + dest._spsLength); if (length < ( sizeof (dest._spsLength) + dest._spsLength + sizeof (dest._ppsLength) + dest._ppsLength + 2 * sizeof (uint32_t))) { FATAL("Not enough data"); return false; } if (!dest.Init( pBuffer + sizeof (dest._spsLength), dest._spsLength, pBuffer + sizeof (dest._spsLength) + dest._spsLength + sizeof (dest._ppsLength), dest._ppsLength)) { FATAL("Unable to init AVC"); return false; } dest._widthOverride = ENTOHLP(pBuffer + sizeof (dest._spsLength) + dest._spsLength + sizeof (dest._ppsLength) + dest._ppsLength); dest._heightOverride = ENTOHLP(pBuffer + sizeof (dest._spsLength) + dest._spsLength + sizeof (dest._ppsLength) + dest._ppsLength + sizeof (uint32_t)); return src.Ignore(sizeof (dest._spsLength) + dest._spsLength + sizeof (dest._ppsLength) + dest._ppsLength + sizeof (uint32_t) + sizeof (uint32_t)); }
bool BaseHTTPProtocol::HandleChunkedContent(IOBuffer &buffer) { //2. We cycle until we don't have any complete chunks anymore //or we hit the 0 bytes chunks (end of chunked content) uint8_t *pBuffer = NULL; uint32_t chunkSize = 0; uint32_t chunkSizeSize = 0; while (GETAVAILABLEBYTESCOUNT(buffer) >= 3) { //1. Get the raw pointer. We need it almost everywhere pBuffer = GETIBPOINTER(buffer); //FINEST("%s", STR(buffer)); chunkSizeSize = 0; //3. Read the string which represents the number of bytes in the chunk for (uint32_t i = 0; i < GETAVAILABLEBYTESCOUNT(buffer) - 1; i++) { //5. Are we at the end of chunk size string? if ((pBuffer[i] == 0x0d) && (pBuffer[i + 1] == 0x0a)) { chunkSizeSize = i + 2; break; } //4. If the chunk size string has more than 10 bytes, we drop it like //is hot! Also test each char to be a hex number. //This is a bogus request/response if (i >= 10 || (!(((pBuffer[i] >= '0') && (pBuffer[i] <= '9')) || ((pBuffer[i] >= 'a') && (pBuffer[i] <= 'f')) || ((pBuffer[i] >= 'A') && (pBuffer[i] <= 'F'))))) { FATAL("Unable to read chunk size length:\n%s", STR(buffer)); return false; } } //7. Test the newly extracted chunk size if (chunkSizeSize == 0) { return true; } //8. Get its actual value and test it as well chunkSize = strtol((char *) pBuffer, NULL, 16); if (chunkSize > HTTP_MAX_CHUNK_SIZE) { FATAL("Chunk size too large. Maximum allowed is %" PRIu32 " and we got %" PRIu32, (uint32_t) HTTP_MAX_CHUNK_SIZE, chunkSize); return false; } //9. Now, we know the chunk size... do we have enough data? if (GETAVAILABLEBYTESCOUNT(buffer) < chunkSizeSize //length of the chunk size string - 2 //substract the 0x particle + 2 //the \r\n that follows the chunk size string + chunkSize //chunk size itself + 2 //the \r\n that follows the data chunk ) { return true; } //10. Update the session decoded bytes count and decoded bytes count _sessionDecodedBytesCount += chunkSize; _decodedBytesCount += chunkSize; if (chunkSize != 0) { //11. Make the copy _contentLength += chunkSize; _inputBuffer.ReadFromBuffer(GETIBPOINTER(buffer) + chunkSizeSize - 2 + 2, chunkSize); } else { //12. This was the last chunk (0 bytes size) _lastChunk = true; } //12. Call the near protocol if (!_pNearProtocol->SignalInputData(_inputBuffer)) { FATAL("Unable to call the next protocol in stack"); return false; } //13. Ignore the bytes from the input buffer DEBUG_HTTP("available bytes before ignore: %" PRIu32, GETAVAILABLEBYTESCOUNT(buffer)); // if (GETAVAILABLEBYTESCOUNT(buffer) == ((uint32_t) chunkSizeSize - 2 + 2 + chunkSize + 2)) { // DEBUG_HTTP("%s", STR(buffer)); // } buffer.Ignore((uint32_t) chunkSizeSize - 2 + 2 + chunkSize + 2); DEBUG_HTTP("available bytes after ignore: %" PRIu32, GETAVAILABLEBYTESCOUNT(buffer)); //14. reset the state if necessary if (TransferCompleted()) { _headers.Reset(); _chunkedContent = false; _lastChunk = false; _contentLength = 0; _state = HTTP_STATE_HEADERS; _sessionDecodedBytesCount = 0; return true; } } return true; }
bool BaseHTTPProtocol::ParseHeaders(IOBuffer& buffer) { //1. We have to have at least 4 bytes (double \r\n) if (GETAVAILABLEBYTESCOUNT(buffer) < 4) { return true; } //2. Detect the headers boundaries uint32_t headersSize = 0; bool markerFound = false; uint8_t *pBuffer = GETIBPOINTER(buffer); for (uint32_t i = 0; i <= GETAVAILABLEBYTESCOUNT(buffer) - 4; i++) { if ((pBuffer[i] == 0x0d) && (pBuffer[i + 1] == 0x0a) && (pBuffer[i + 2] == 0x0d) && (pBuffer[i + 3] == 0x0a)) { markerFound = true; headersSize = i; break; } if (i >= HTTP_MAX_HEADERS_SIZE) { FATAL("Headers section too long"); return false; } } //3. Are the boundaries correct? //Do we have enough data to parse the headers? if (headersSize == 0) { if (markerFound) return false; else return true; } //4. Get the raw headers and plit it into lines string rawHeaders = string((char *) GETIBPOINTER(buffer), headersSize); vector<string> lines; split(rawHeaders, "\r\n", lines); if (lines.size() == 0) { FATAL("Incorrect HTTP request"); return false; } //4. Get the fisrt line and parse it. This is either a status code //for a previous request made by us, or the request that we just received if (!ParseFirstLine(lines[0], _headers[HTTP_FIRST_LINE])) { FATAL("Unable to parse the first line"); return false; } //5. Consider the rest of the lines as key: value pairs and store them //0. Reset the headers _headers[HTTP_HEADERS].IsArray(false); for (uint32_t i = 1; i < lines.size(); i++) { string line = lines[i]; string::size_type splitterPos = line.find(": "); if ((splitterPos == string::npos) || (splitterPos == 0) || (splitterPos == line.size() - 2)) { FATAL("Invalid header line"); return false; } _headers[HTTP_HEADERS][line.substr(0, splitterPos)] = line.substr(splitterPos + 2, string::npos); } //6. default a transfer type to Content-Length: 0 if necessary if ((!_headers[HTTP_HEADERS].HasKey(HTTP_HEADERS_CONTENT_LENGTH, false)) && (!_headers[HTTP_HEADERS].HasKey(HTTP_HEADERS_TRANSFER_ENCODING, false))) { _headers[HTTP_HEADERS][HTTP_HEADERS_CONTENT_LENGTH] = "0"; } //7. read the transfer type and set this request or response flags if (_headers[HTTP_HEADERS].HasKey(HTTP_HEADERS_CONTENT_LENGTH, false)) { string contentLengthString = _headers[HTTP_HEADERS].GetValue( HTTP_HEADERS_CONTENT_LENGTH, false); replace(contentLengthString, " ", ""); if (!isNumeric(contentLengthString)) { FATAL("Invalid HTTP headers:\n%s", STR(_headers.ToString())); return false; } _contentLength = atoi(STR(contentLengthString)); _chunkedContent = false; _lastChunk = false; } else if (_headers[HTTP_HEADERS].HasKey(HTTP_HEADERS_TRANSFER_ENCODING, false)) { if (lowerCase(_headers[HTTP_HEADERS].GetValue(HTTP_HEADERS_TRANSFER_ENCODING, false)) != lowerCase(HTTP_HEADERS_TRANSFER_ENCODING_CHUNKED)) { FATAL("The only supported %s is %s", HTTP_HEADERS_TRANSFER_ENCODING, HTTP_HEADERS_TRANSFER_ENCODING_CHUNKED); return false; } _chunkedContent = true; _lastChunk = false; _contentLength = 0; } //7. Advance the state and ignore the headers part from the buffer _state = HTTP_STATE_PAYLOAD; buffer.Ignore(headersSize + 4); return Authenticate(); }
bool OutboundRTMPProtocol::PerformHandshakeStage2(IOBuffer &inputBuffer, bool encrypted) { if (encrypted || _pProtocolHandler->ValidateHandshake()) { if (!VerifyServer(inputBuffer)) { FATAL("Unable to verify server"); return false; } } uint8_t *pInputBuffer = GETIBPOINTER(inputBuffer) + 1; uint32_t serverDHOffset = GetDHOffset(pInputBuffer, _usedScheme); if (_pDHWrapper == NULL) { FATAL("dh wrapper not initialized"); return false; } DEBUG_HANDSHAKE("CLIENT: 1. serverDHOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; serverPublicKey: %s", serverDHOffset, _usedScheme, STR(hex(pInputBuffer + serverDHOffset, 128))); if (!_pDHWrapper->CreateSharedKey(pInputBuffer + serverDHOffset, 128)) { FATAL("Unable to create shared key"); return false; } uint8_t secretKey[128]; if (!_pDHWrapper->CopySharedKey(secretKey, sizeof (secretKey))) { FATAL("Unable to compute shared"); return false; } DEBUG_HANDSHAKE("CLIENT: 2. secretKey: %s", STR(hex(secretKey, 128))); if (encrypted) { _pKeyIn = new RC4_KEY; _pKeyOut = new RC4_KEY; InitRC4Encryption( secretKey, (uint8_t*) & pInputBuffer[serverDHOffset], _pClientPublicKey, _pKeyIn, _pKeyOut); uint8_t data[1536]; RC4(_pKeyIn, 1536, data, data); RC4(_pKeyOut, 1536, data, data); } delete _pDHWrapper; _pDHWrapper = NULL; uint32_t serverDigestOffset = GetDigestOffset(pInputBuffer, _usedScheme); DEBUG_HANDSHAKE("CLIENT: 3. serverDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8, serverDigestOffset, _usedScheme); if (_pOutputBuffer == NULL) { _pOutputBuffer = new uint8_t[1536]; } else { delete[] _pOutputBuffer; _pOutputBuffer = new uint8_t[1536]; } for (uint32_t i = 0; i < 1536; i++) { _pOutputBuffer[i] = rand() % 256; } uint8_t * pChallangeKey = new uint8_t[512]; HMACsha256(pInputBuffer + serverDigestOffset, 32, genuineFPKey, 62, pChallangeKey); uint8_t * pDigest = new uint8_t[512]; HMACsha256(_pOutputBuffer, 1536 - 32, pChallangeKey, 32, pDigest); memcpy(_pOutputBuffer + 1536 - 32, pDigest, 32); DEBUG_HANDSHAKE("CLIENT: 4. clientChallange: %s", STR(hex(pDigest, 32))); delete[] pChallangeKey; delete[] pDigest; _outputBuffer.ReadFromBuffer(_pOutputBuffer, 1536); delete[] _pOutputBuffer; _pOutputBuffer = NULL; _rtmpState = RTMP_STATE_DONE; return true; }
bool BaseInFileStream::SendCodecs() { //1. Read the first frame MediaFrame frame1; if (!_pSeekFile->SeekTo(_framesBaseOffset + 0 * sizeof (MediaFrame))) { FATAL("Unablt to seek inside seek file"); return false; } if (!_pSeekFile->ReadBuffer((uint8_t *) & frame1, sizeof (MediaFrame))) { FATAL("Unable to read frame from seeking file"); return false; } //2. Read the second frame MediaFrame frame2; if (!_pSeekFile->SeekTo(_framesBaseOffset + 1 * sizeof (MediaFrame))) { FATAL("Unablt to seek inside seek file"); return false; } if (!_pSeekFile->ReadBuffer((uint8_t *) & frame2, sizeof (MediaFrame))) { FATAL("Unable to read frame from seeking file"); return false; } //3. Read the current frame to pickup the timestamp from it MediaFrame currentFrame; if (!_pSeekFile->SeekTo(_framesBaseOffset + _currentFrameIndex * sizeof (MediaFrame))) { FATAL("Unablt to seek inside seek file"); return false; } if (!_pSeekFile->ReadBuffer((uint8_t *) & currentFrame, sizeof (MediaFrame))) { FATAL("Unable to read frame from seeking file"); return false; } //4. Is the first frame a codec setup? //If not, the second is not a codec setup for sure if (!frame1.isBinaryHeader) { _audioVideoCodecsSent = true; return true; } //5. Build the buffer for the first frame IOBuffer buffer; if (!BuildFrame(_pFile, frame1, buffer)) { FATAL("Unable to build the frame"); return false; } //6. Do the feedeng with the first frame if (!_pOutStreams->info->FeedData( GETIBPOINTER(buffer), //pData GETAVAILABLEBYTESCOUNT(buffer), //dataLength 0, //processedLength GETAVAILABLEBYTESCOUNT(buffer), //totalLength currentFrame.absoluteTime, //absoluteTimestamp frame1.type == MEDIAFRAME_TYPE_AUDIO //isAudio )) { FATAL("Unable to feed audio data"); return false; } //7. Is the second frame a codec setup? if (!frame2.isBinaryHeader) { _audioVideoCodecsSent = true; return true; } //8. Build the buffer for the second frame buffer.IgnoreAll(); if (!BuildFrame(_pFile, frame2, buffer)) { FATAL("Unable to build the frame"); return false; } //9. Do the feedeng with the second frame if (!_pOutStreams->info->FeedData( GETIBPOINTER(buffer), //pData GETAVAILABLEBYTESCOUNT(buffer), //dataLength 0, //processedLength GETAVAILABLEBYTESCOUNT(buffer), //totalLength currentFrame.absoluteTime, //absoluteTimestamp frame2.type == MEDIAFRAME_TYPE_AUDIO //isAudio )) { FATAL("Unable to feed audio data"); return false; } //10. Done _audioVideoCodecsSent = true; return true; }
bool BaseInFileStream::Feed() { //1. Are we in paused state? if (_paused) return true; //2. First, send audio and video codecs if (!_audioVideoCodecsSent) { if (!SendCodecs()) { FATAL("Unable to send audio codec"); return false; } } //2. Determine if the client has enough data on the buffer and continue //or stay put uint32_t elapsedTime = (uint32_t) (time(NULL) - _startFeedingTime); if ((int32_t) _totalSentTime - (int32_t) elapsedTime >= _clientSideBufferLength) { return true; } //3. Test to see if we have sent the last frame if (_currentFrameIndex >= _totalFrames) { FINEST("Done streaming file"); _pOutStreams->info->SignalStreamCompleted(); _paused = true; return true; } //FINEST("_totalSentTime: %.2f; _playLimit: %.2f", (double) _totalSentTime, _playLimit); if (_playLimit >= 0) { if (_playLimit < (double) _totalSentTime) { FINEST("Done streaming file"); _pOutStreams->info->SignalStreamCompleted(); _paused = true; return true; } } //4. Read the current frame from the seeking file if (!_pSeekFile->SeekTo(_framesBaseOffset + _currentFrameIndex * sizeof (MediaFrame))) { FATAL("Unablt to seek inside seek file"); return false; } if (!_pSeekFile->ReadBuffer((uint8_t *) & _currentFrame, sizeof (_currentFrame))) { FATAL("Unable to read frame from seeking file"); return false; } //5. Take care of metadata if (_currentFrame.type == MEDIAFRAME_TYPE_DATA) { _currentFrameIndex++; if (!FeedMetaData(_pFile, _currentFrame)) { FATAL("Unable to feed metadata"); return false; } return Feed(); } //6. get our hands on the correct buffer, depending on the frame type: audio or video IOBuffer &buffer = _currentFrame.type == MEDIAFRAME_TYPE_AUDIO ? _audioBuffer : _videoBuffer; //7. Build the frame if (!BuildFrame(_pFile, _currentFrame, buffer)) { FATAL("Unable to build the frame"); return false; } //8. Compute the timestamp _totalSentTime = (uint32_t) (_currentFrame.absoluteTime / 1000) - _totalSentTimeBase; //9. Do the feedeng if (!_pOutStreams->info->FeedData( GETIBPOINTER(buffer), //pData GETAVAILABLEBYTESCOUNT(buffer), //dataLength 0, //processedLength GETAVAILABLEBYTESCOUNT(buffer), //totalLength (uint32_t) _currentFrame.absoluteTime, //absoluteTimestamp _currentFrame.type == MEDIAFRAME_TYPE_AUDIO //isAudio )) { FATAL("Unable to feed audio data"); return false; } //10. Discard the data buffer.IgnoreAll(); //11. Increment the frame index _currentFrameIndex++; //12. Done. We either feed again if frame length was 0 //or just return true if (_currentFrame.length == 0) { return Feed(); } else { return true; } }