Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
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;
}
Ejemplo n.º 5
0
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;
	}
}
Ejemplo n.º 6
0
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;
}
Ejemplo n.º 7
0
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();
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
0
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);
}
Ejemplo n.º 11
0
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;
}
Ejemplo n.º 12
0
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;
		}
	}
Ejemplo n.º 13
0
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();
}
Ejemplo n.º 14
0
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;
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
0
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();
}
Ejemplo n.º 17
0
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;
}
Ejemplo n.º 18
0
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();
}
Ejemplo n.º 19
0
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;
	}
}
Ejemplo n.º 20
0
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);
	}
}
Ejemplo n.º 22
0
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);
}
Ejemplo n.º 23
0
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();
}
Ejemplo n.º 24
0
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;
}
Ejemplo n.º 25
0
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));
}
Ejemplo n.º 26
0
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;
}
Ejemplo n.º 27
0
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();
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
0
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;
}
Ejemplo n.º 30
0
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;
	}
}