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 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 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 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; }
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; } } }
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; }
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; }
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 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 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); } }
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; }
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 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; }
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; } } } } }
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; } } }
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; }
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; } } }