Exemplo n.º 1
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;
}
Exemplo 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;
}
Exemplo n.º 3
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;
	}
}
Exemplo n.º 4
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;
}
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;
}
Exemplo n.º 6
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;
}
bool OutboundRTMPProtocol::PerformHandshake(IOBuffer &buffer) {
	switch (_rtmpState) {
		case RTMP_STATE_NOT_INITIALIZED:
		{
			_encrypted = (VariantType) _customParameters[CONF_PROTOCOL] == V_STRING &&
					_customParameters[CONF_PROTOCOL] == CONF_PROTOCOL_OUTBOUND_RTMPE;
			_usedScheme = _encrypted ? 1 : 0;

			if ((VariantType) _customParameters[CONF_PROTOCOL] == V_STRING &&
					_customParameters[CONF_PROTOCOL] == CONF_PROTOCOL_OUTBOUND_RTMPE) {
				return PerformHandshakeStage1(true);
			} else {
				return PerformHandshakeStage1(false);
			}
		}
		case RTMP_STATE_CLIENT_REQUEST_SENT:
		{
			if (GETAVAILABLEBYTESCOUNT(buffer) < 3073)
				return true;

			if (!PerformHandshakeStage2(buffer, _encrypted)) {
				FATAL("Unable to handshake");
				return false;
			}

			if (_pFarProtocol != NULL) {
				if (!_pFarProtocol->EnqueueForOutbound()) {
					FATAL("Unable to signal output data");
					return false;
				}
			}

			if (_pKeyIn != NULL && _pKeyOut != NULL) {
				//insert the RTMPE protocol in the current protocol stack
				BaseProtocol *pFarProtocol = GetFarProtocol();
				RTMPEProtocol *pRTMPE = new RTMPEProtocol(_pKeyIn, _pKeyOut,
						GETAVAILABLEBYTESCOUNT(_outputBuffer));
				ResetFarProtocol();
				pFarProtocol->SetNearProtocol(pRTMPE);
				pRTMPE->SetNearProtocol(this);
				//FINEST("New protocol chain: %s", STR(*pFarProtocol));
			}

			if (!buffer.Ignore(3073)) {
				FATAL("Unable to ignore 3073 bytes");
				return false;
			}
			_handshakeCompleted = true;
			return true;
		}
		default:
		{
			FATAL("Invalid RTMP state: %d", _rtmpState);
			return false;
		}
	}
}
Exemplo n.º 8
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;
}
bool UXDomainSocketAppProtocolHandler::EventSocket(UnixDomainSocketProtocol *pFrom, IOBuffer &buffer) {
  uint32_t buflen = GETAVAILABLEBYTESCOUNT(buffer);

  while (buflen>=16) {
    uint8_t* pBuf=GETIBPOINTER(buffer);

    CHK_ALIGN4(pBuf);
    uint32_t msglen=*((uint32_t*)(pBuf+12));
    uint32_t total = PADDED_TOTAL(msglen+16);
    string data;

    if (buflen < total) {
      break;
    }
    uint16_t type=*((uint16_t*)(pBuf));
    uint32_t subType=*((uint16_t*)(pBuf+2));
    uint64_t eventInfo=0;

    DEBUG ("type:%d, subtype:%d", type, subType);
    //message has data
    if (msglen) {
      string temp((char*)(pBuf+16), msglen);
      data=temp;
    }
    QICStreamerApplication *pApp=
        static_cast<QICStreamerApplication*>(GetApplication());

    switch (type) {
      case (CLOUD_MSG_ERROR):
        pApp->SendError(subType, data);
        HardwareManager::SetStatus(subType, false);
        break;
      case (CLOUD_MSG_EVENT):
        eventInfo=*((uint64_t*)(pBuf+4));
        pApp->SendEvent(subType, eventInfo, data);
        break;
      case (DEVICE_EVENT):
        {
          RestCLIMessage restMessage;
          uint32_t start=0;
          ActionRouter *pActionRouter=pApp->GetActionRouter();
          Variant::DeserializeFromJSON(data, restMessage.request, start);
          pActionRouter->RouteRequestAction(restMessage);
        }
        break;
    }
    buffer.Ignore(total);
    buflen = GETAVAILABLEBYTESCOUNT(buffer);
  }

  return true;
}
Exemplo n.º 10
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;
}
bool UXDomainSocketAppProtocolHandler::IpcEventSocket(UnixDomainSocketProtocol *pFrom, IOBuffer &buffer) {
    uint32_t length = GETAVAILABLEBYTESCOUNT(buffer);
    uint8_t *pBuf = GETIBPOINTER(buffer);
    BaseAVCVideoCapture *_pAVCCaptureInstance;

    _pAVCCaptureInstance = reinterpret_cast<BaseAVCVideoCapture *>(HardwareManager::GetHardwareInstance(HT_VIDEO_AVC));

    printf ("buf length (%d): %s\n", length, pBuf);
    buffer.Ignore(length);

    _pAVCCaptureInstance->VerifyResolution(640,360);
    _pAVCCaptureInstance->SetResolution(640,360);

    UnixDomainSocketManager::SendResponseToIpcEvent ("2");

    return true;
}
Exemplo n.º 12
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);
}
Exemplo n.º 13
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;
}
Exemplo n.º 14
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));
}
bool UXDomainSocketAppProtocolHandler::InfoSocket(UnixDomainSocketProtocol *pFrom, IOBuffer &buffer) {
  uint32_t avail=GETAVAILABLEBYTESCOUNT(buffer);
  QICStreamerApplication* pApp=
      reinterpret_cast<QICStreamerApplication*>(GetApplication());


  //DEBUG ("data:%s", STR(buffer.ToString()));
  while (avail>=12) {
    uint8_t* pBuf=GETIBPOINTER(buffer);
    CHK_ALIGN4(pBuf);
    uint32_t type=*((uint32_t*)(pBuf));
    uint32_t msgId=*((uint32_t*)(pBuf+4));
    uint32_t length=*((uint32_t*)(pBuf+8));
    uint32_t total=PADDED_TOTAL(length+12);

    if (avail<total)
      break;

    UnixDomainSocketManager::SendDataToUXCallback(msgId, (uint8_t*)(GETIBPOINTER(buffer)+12), length);

    if (type==INFO_OP_SYSTEMINFO) {
      pApp->SendInfo(INFO_SYSTEM, (uint8_t*)(GETIBPOINTER(buffer)+12), length);
    }
    else if (type==INFO_OP_CMD && length) {
      uint32_t errorCode=*((uint32_t*)(pBuf+12));

      if (errorCode!=EC_RESERVED) {
        pApp->SendError(ERROR_CODE(errorCode), ERROR_DESCRIPTION(errorCode));
      }
    }

    buffer.Ignore(total);
    avail=GETAVAILABLEBYTESCOUNT(buffer);
  }
  return true;
}
inline void UXDomainSocketAppProtocolHandler::ParseUXDomainSocketData(queue<UXSocketData*> &socketData, IOBuffer &buffer) {
  uint32_t length = GETAVAILABLEBYTESCOUNT(buffer);

  while (length>=12) {
    UXSocketData *pSocketData = (UXSocketData*) new UXSocketData();
    uint8_t *pBuf = GETIBPOINTER(buffer);

    CHK_ALIGN4(pBuf);
    pSocketData->type = (*pBuf);
    pSocketData->id = *((uint32_t*)(pBuf+4));
    pSocketData->dataLength = *((uint32_t*)(pBuf+8));
    uint32_t total=PADDED_TOTAL(pSocketData->dataLength+12);

    if (length<total) {
      delete pSocketData;
      break;
    } else {
      pSocketData->dataBuffer.ReadFromBuffer(pBuf+12, pSocketData->dataLength);
      buffer.Ignore(total);
      socketData.push(pSocketData);
    }
    length = GETAVAILABLEBYTESCOUNT(buffer);
  }
}
Exemplo n.º 17
0
bool InboundHTTP4RTMP::SignalInputData(IOBuffer &buffer) {
	//1. Get the HTTP far protool and test to see if it has ContentLength
	InboundHTTPProtocol *pHTTP = (InboundHTTPProtocol *) _pFarProtocol;
	if (pHTTP == NULL || pHTTP->GetContentLength() == 0) {
		FATAL("Invalid HTTP request");
		return false;
	}

	//2. Test it and see if all the data was transfered
	if (!pHTTP->TransferCompleted()) {
		return true;
	}

	//3. Get the HTTP request
	Variant request = pHTTP->GetHeaders();

	//4. Is this a keep-alive?
	pHTTP->SetDisconnectAfterTransfer(
			request[HTTP_HEADERS][HTTP_HEADERS_CONNECTION]
			!= HTTP_HEADERS_CONNECTION_KEEP_ALIVE);
	DeleteNearProtocol(false);

	//4. Get the URL
	string url = request[HTTP_FIRST_LINE][HTTP_URL];

	//5. split it in meaningful parts
	vector<string> parts;
	split(url, "/", parts);
	if (parts.size() < 2) {
		FATAL("Invalid request:\n%s", STR(request.ToString()));
		return false;
	}

	//7. Do the dammage
	bool result;
	if (parts[1] == "fcs") {
		result = ProcessFcs(parts);
		buffer.Ignore(pHTTP->GetContentLength());
	} else if (parts[1] == "open") {
		result = ProcessOpen(parts);
		buffer.Ignore(pHTTP->GetContentLength());
	} else if (parts[1] == "idle") {
		result = ProcessIdle(parts);
		buffer.Ignore(pHTTP->GetContentLength());
	} else if (parts[1] == "send") {
		if (GETAVAILABLEBYTESCOUNT(buffer) < 1)
			return false;
		_inputBuffer.ReadFromBuffer(GETIBPOINTER(buffer), pHTTP->GetContentLength());
		buffer.Ignore(pHTTP->GetContentLength());
		result = ProcessSend(parts);
	} else {
		FATAL("Invalid command: %s", STR(parts[1]));
		result = false;
	}

	//8. Cleanup
	if (!result) {
		DeleteNearProtocol(true);
		EnqueueForDelete();
	}

	//9. Done
	return result;
}
Exemplo n.º 18
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;
}
Exemplo n.º 19
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();
}
Exemplo n.º 20
0
bool RTCPProtocol::SignalInputData(IOBuffer &buffer, sockaddr_in *pPeerAddress) {
	//0. Save the last known address
	if (&_lastAddress != pPeerAddress) {
		_lastAddress = *pPeerAddress;
		_validLastAddress = true;
	}

	//1. Parse the SR
	uint8_t *pBuffer = GETIBPOINTER(buffer);
	uint32_t bufferLength = GETAVAILABLEBYTESCOUNT(buffer);
	while (bufferLength > 0) {
		if (bufferLength < 4) {
			buffer.IgnoreAll();
			return true;
		}

		uint8_t PT = pBuffer[1];
		uint16_t len = ENTOHSP(pBuffer + 2);
		len = (len + 1)*4;
		if (len > bufferLength) {
			buffer.IgnoreAll();
			return true;
		}

		switch (PT) {
			case 200: //SR
			{
				if (len < 28) {
					buffer.IgnoreAll();
					return true;
				}
				uint32_t ntpSec = ENTOHLP(pBuffer + 8) - 2208988800UL;
				uint32_t ntpFrac = ENTOHLP(pBuffer + 12);
				uint64_t ntpMicroseconds = (uint32_t) (((double) ntpFrac / (double) (0x100000000LL))*1000000.0);
				ntpMicroseconds += ((uint64_t) ntpSec)*1000000;
				uint32_t rtpTimestamp = ENTOHLP(pBuffer + 16);
				if (_pConnectivity == NULL) {
					FATAL("No connectivity, unable to send SR");
					return false;
				}
				_pConnectivity->ReportSR(ntpMicroseconds, rtpTimestamp, _isAudio);

				_lsr = ENTOHLP(pBuffer + 10);

				if (!_pConnectivity->SendRR(_isAudio)) {
					FATAL("Unable to send RR");
					_pConnectivity->EnqueueForDelete();
					_pConnectivity = NULL;
					return false;
				}
				break;
			}
			case 203: //BYE
			{
				if (_pConnectivity == NULL) {
					FATAL("No connectivity, BYE packet ignored");
					return false;
				}
				_pConnectivity->EnqueueForDelete();
				_pConnectivity = NULL;
				break;
			}
			default:
			{
				break;
			}
		}

		buffer.Ignore(len);

		pBuffer = GETIBPOINTER(buffer);
		bufferLength = GETAVAILABLEBYTESCOUNT(buffer);
	}

	return true;
}
Exemplo n.º 21
0
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;
				}
			}
		}
	}
}
Exemplo n.º 22
0
bool InboundRTMPProtocol::PerformHandshake(IOBuffer &buffer) {
	switch (_rtmpState) {
		case RTMP_STATE_NOT_INITIALIZED:
		{
			if (GETAVAILABLEBYTESCOUNT(buffer) < 1537) {
				return true;
			}
			uint8_t handshakeType = GETIBPOINTER(buffer)[0];
			if (!buffer.Ignore(1)) {
				FATAL("Unable to ignore one byte");
				return false;
			}

			_currentFPVersion = ENTOHLP(GETIBPOINTER(buffer) + 4);

			switch (handshakeType) {
				case 3: //plain
				{
					return PerformHandshake(buffer, false);
				}
				case 6: //encrypted
				{
					return PerformHandshake(buffer, true);
				}
				default:
				{
					FATAL("Handshake type not implemented: %hhu", handshakeType);
					return false;
				}
			}
		}
		case RTMP_STATE_SERVER_RESPONSE_SENT:
		{
			if (GETAVAILABLEBYTESCOUNT(buffer) < 1536) {
				return true;
			} else {
				//ignore the client's last handshake part
				if (!buffer.Ignore(1536)) {
					FATAL("Unable to ignore inbound data");
					return false;
				}
				_handshakeCompleted = true;
				_rtmpState = RTMP_STATE_DONE;

				if (_pKeyIn != NULL && _pKeyOut != NULL) {
					//insert the RTMPE protocol in the current protocol stack
					BaseProtocol *pFarProtocol = GetFarProtocol();
					RTMPEProtocol *pRTMPE = new RTMPEProtocol(_pKeyIn, _pKeyOut);
					ResetFarProtocol();
					pFarProtocol->SetNearProtocol(pRTMPE);
					pRTMPE->SetNearProtocol(this);
					FINEST("New protocol chain: %s", STR(*pFarProtocol));

					//decrypt the leftovers
					RC4(_pKeyIn, GETAVAILABLEBYTESCOUNT(buffer),
							GETIBPOINTER(buffer),
							GETIBPOINTER(buffer));
				}

				return true;
			}
		}
		default:
		{
			FATAL("Invalid RTMP state: %d", _rtmpState);
			return false;
		}
	}
}
Exemplo n.º 23
0
bool InboundAESProtocol::SignalInputData(IOBuffer &buffer) {
	//2. Get the size
	int32_t size = GETAVAILABLEBYTESCOUNT(buffer);

	//3. Get the multiple of block size
	int32_t safeSize = (size / 16)*16;

	//4. Get the outputBufferSize
	int32_t bufferSize = safeSize + 16;

	//3. Do we have data?
	if (size == 0)
		return true;

	//4. Make room for the descrypted data
	_tempBuffer.IgnoreAll();
	_tempBuffer.EnsureSize(bufferSize);

	//5. Decrypt
	uint8_t *pTempData = GETIBPOINTER(_tempBuffer);
	int decryptedSize = 0;
	int decryptedFinalSize = 0;
	uint32_t padding = 0;

	EVP_DecryptUpdate(&_decContex, pTempData, &decryptedSize, GETIBPOINTER(buffer), safeSize);
	_totalDecrypted += decryptedSize;

	//6. Decrypt leftovers
	bool transferCompleted = false;
	if (((HTTPBufferProtocol *) GetFarProtocol())->TransferCompleted()) {
		transferCompleted = true;
		EVP_DecryptFinal_ex(&_decContex,
				pTempData + decryptedSize,
				&decryptedFinalSize);
		_totalDecrypted += decryptedFinalSize;
		WARN("chunkSize hardcoded to 188 bytes");
		uint32_t chunkSize = 188;
		padding = _totalDecrypted - (((uint32_t) (_totalDecrypted / chunkSize)) * chunkSize);
		if (size != decryptedSize + decryptedFinalSize) {
			FINEST("size: %d; safeSize: %d; bufferSize: %d; decryptedSize: %d; decryptedFinalSize: %d",
					size,
					safeSize,
					bufferSize,
					decryptedSize,
					decryptedFinalSize);
			FATAL("Malformed AES content. It should always be 16 bytes aligned");
			return false;
		}
	}

	//7. Ignore decrypted data
	buffer.Ignore(decryptedSize + decryptedFinalSize);

	//8. Prepare the buffer for the next protocol in the stack
	_inputBuffer.ReadFromBuffer(pTempData, decryptedSize + decryptedFinalSize - padding);

	//9. Get the context
	ClientContext *pContext = GetContext();
	if (pContext == NULL) {
		FATAL("Unable to get context");
		return false;
	}

	//10. Feed the data
	if (!pContext->SignalAVDataAvailable(_inputBuffer)) {
		FATAL("Unable to signal ts A/V data available");
		return false;
	}

	//11. Done
	return true;
}
Exemplo n.º 24
0
bool Header::Read(uint32_t channelId, uint8_t type, IOBuffer &buffer,
		uint32_t availableBytes) {
	ht = type;
	ci = channelId;

	switch (ht) {
		case HT_FULL:
		{
			isAbsolute = true;
			if (availableBytes < 11) {
				readCompleted = false;
				return true;
			}
			memcpy(hf.datac + 1, GETIBPOINTER(buffer), 11);
			hf.s.ts = ENTOHL(hf.s.ts)&0x00ffffff; //----MARKED-LONG---
			hf.s.ml = ENTOHL(hf.s.ml) >> 8; //----MARKED-LONG---

			if (hf.s.ts == 0x00ffffff) {
				skip4bytes = true;
				if (availableBytes < 15) {
					readCompleted = false;
					return true;
				}
				hf.s.ts = ENTOHLP(GETIBPOINTER(buffer) + 11);
				readCompleted = true;
				return buffer.Ignore(15);
			} else {
				skip4bytes = false;
				readCompleted = true;
				return buffer.Ignore(11);
			}
		}
		case HT_SAME_STREAM:
		{
			isAbsolute = false;
			if (availableBytes < 7) {
				readCompleted = false;
				return true;
			}
			memcpy(hf.datac + 1, GETIBPOINTER(buffer), 7);
			hf.s.ts = ENTOHL(hf.s.ts)&0x00ffffff; //----MARKED-LONG---
			hf.s.ml = ENTOHL(hf.s.ml) >> 8; //----MARKED-LONG---

			if (hf.s.ts == 0x00ffffff) {
				skip4bytes = true;
				if (availableBytes < 11) {
					readCompleted = false;
					return true;
				}
				hf.s.ts = ENTOHLP(GETIBPOINTER(buffer) + 7);
				readCompleted = true;
				return buffer.Ignore(11);
			} else {
				skip4bytes = false;
				readCompleted = true;
				return buffer.Ignore(7);
			}
		}
		case HT_SAME_LENGTH_AND_STREAM:
		{
			isAbsolute = false;
			if (availableBytes < 3) {
				readCompleted = false;
				return true;
			}
			memcpy(hf.datac + 1, GETIBPOINTER(buffer), 3);
			hf.s.ts = ENTOHL(hf.s.ts)&0x00ffffff; //----MARKED-LONG---

			if (hf.s.ts == 0x00ffffff) {
				skip4bytes = true;
				if (availableBytes < 7) {
					readCompleted = false;
					return true;
				}
				hf.s.ts = ENTOHLP(GETIBPOINTER(buffer) + 3);
				readCompleted = true;
				return buffer.Ignore(7);
			} else {
				skip4bytes = false;
				readCompleted = true;
				return buffer.Ignore(3);
			}
		}
		case HT_CONTINUATION:
		{
			isAbsolute = false;
			if (skip4bytes) {
				if (availableBytes < 4) {
					readCompleted = false;
					return true;
				}
				readCompleted = true;
				return buffer.Ignore(4);
			} else {
				readCompleted = true;
				return true;
			}
		}
		default:
		{
			FATAL("Invalid header type: %hhu", ht);
			return false;
		}
	}
}