bool InboundMJPGHTTPStreamProtocol::PutData(uint8_t *pBuffer, uint32_t length) { int obuflen = 0; if (!_headersSent) { _outputBuffer.ReadFromString("HTTP/1.0 200 OK\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_SERVER": "HTTP_HEADERS_SERVER_US"\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_X_POWERED_BY": "HTTP_HEADERS_X_POWERED_BY_US"\r\n"); _outputBuffer.ReadFromString("Connection: close\r\n"); _outputBuffer.ReadFromString("Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n"); _outputBuffer.ReadFromString("Pragma: no-cache\r\n"); _outputBuffer.ReadFromString("Expires: Mon, 3 Jan 2000 00:00:00 GMT\r\n"); _outputBuffer.ReadFromString("Content-Type: multipart/x-mixed-replace;boundary="BOUNDARY"\r\n"); _outputBuffer.ReadFromString("\r\n"); _outputBuffer.ReadFromString("--"BOUNDARY"\r\n"); EnqueueForOutbound(); _headersSent = true; } obuflen = GETAVAILABLEBYTESCOUNT(_outputBuffer); if(obuflen > MAX_OUTPUT_BUFFER_SIZE){ FATAL("output congestion! drop frame now %d", obuflen); _outputBuffer.IgnoreAll(); } _outputBuffer.ReadFromString("Content-Type: image/jpeg\r\n"); _outputBuffer.ReadFromString(format("Content-Length: %d\r\n", length)); _outputBuffer.ReadFromString("\r\n"); _outputBuffer.ReadFromBuffer(pBuffer, length); _outputBuffer.ReadFromString("\r\n--"BOUNDARY"\r\n"); return EnqueueForOutbound(); }
bool OutboundSSLProtocol::DoHandshake() { if (_sslHandshakeCompleted) return true; int32_t errorCode = SSL_ERROR_NONE; errorCode = SSL_connect(_pSSL); if (errorCode < 0) { int32_t error = SSL_get_error(_pSSL, errorCode); if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE) { FATAL("Unable to connect SSL: %d; %s", error, STR(GetSSLErrors())); return false; } } _sslHandshakeCompleted = SSL_is_init_finished(_pSSL); if (!PerformIO()) { FATAL("Unable to perform I/O"); return false; } if (_sslHandshakeCompleted) return EnqueueForOutbound(); return true; }
bool InboundMJPGHTTPStreamProtocol::Send404NotFound() { _outputBuffer.ReadFromString("HTTP/1.0 404 Not found\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_SERVER": "HTTP_HEADERS_SERVER_US"\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_X_POWERED_BY": "HTTP_HEADERS_X_POWERED_BY_US"\r\n\r\n"); if (!EnqueueForOutbound()) { FATAL("Unable to enqueue for outbound"); return false; } GracefullyEnqueueForDelete(); return true; }
bool InboundJSONCLIProtocol::SendMessage(Variant &message) { string json; if (!message.SerializeToJSON(json)) { FATAL("Unable to serialize to JSON"); return false; } json += "\r\n"; if (_useLengthPadding) { uint32_t size = EHTONL((uint32_t) json.length()); _outputBuffer.ReadFromBuffer((uint8_t *) & size, 4); } _outputBuffer.ReadFromString(json); return EnqueueForOutbound(); }
bool InboundXMLCLIProtocol::SendMessage(Variant &message) { string xml; #if (defined(HAS_TINYXML)) if (!message.SerializeToXml(xml, true)) { FATAL("Unable to serialize to XML"); return false; } xml += "\r\n\r\n"; if (_useLengthPadding) { uint32_t size = EHTONL((uint32_t) xml.length()); _outputBuffer.ReadFromBuffer((uint8_t *) & size, 4); } _outputBuffer.ReadFromString(xml); return EnqueueForOutbound(); #else FATAL("Unable to serialize to XML, must enable tinyXML"); return false; #endif }
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 InboundMJPGHTTPStreamProtocol::SendCrossDomain() { if (!fileExists(_crossDomainFile)) { FATAL("cross domain file %s not found", STR(_crossDomainFile)); return Send404NotFound(); } File cd; if (!cd.Initialize(_crossDomainFile, FILE_OPEN_MODE_READ)) { FATAL("cross domain file %s could not be read", STR(_crossDomainFile)); return Send404NotFound(); } _outputBuffer.ReadFromString("HTTP/1.0 200 OK\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_SERVER": "HTTP_HEADERS_SERVER_US"\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_X_POWERED_BY": "HTTP_HEADERS_X_POWERED_BY_US"\r\n"); _outputBuffer.ReadFromString(HTTP_HEADERS_CONTENT_TYPE": text/xml\r\n"); _outputBuffer.ReadFromString(format("%s: %"PRIu64"\r\n\r\n", HTTP_HEADERS_CONTENT_LENGTH, cd.Size())); _outputBuffer.ReadFromFs(cd, cd.Size()); //FINEST("_outputBuffer:\n%s", STR(_outputBuffer)); if (!EnqueueForOutbound()) { FATAL("Unable to enqueue for outbound"); return false; } GracefullyEnqueueForDelete(); return true; }
bool BaseVariantProtocol::Send(Variant &variant) { //1. Do we have a protocol? if (_pFarProtocol == NULL) { FATAL("This protocol is not linked"); return false; } //2. Save the variant _lastSent = variant; //3. Depending on the far protocol, we do different stuff string rawContent = ""; switch (_pFarProtocol->GetType()) { case PT_TCP: { //5. Serialize it if (!Serialize(rawContent, variant)) { FATAL("Unable to serialize variant"); return false; } _outputBuffer.ReadFromRepeat(0, 4); uint32_t rawContentSize = rawContent.size(); EHTONLP(GETIBPOINTER(_outputBuffer), rawContentSize); _outputBuffer.ReadFromString(rawContent); //6. enqueue for outbound if (!EnqueueForOutbound()) { FATAL("Unable to enqueue for outbound"); return false; } GracefullyEnqueueForDelete(); return true; } case PT_OUTBOUND_HTTP: { #ifdef HAS_PROTOCOL_HTTP //7. This is a HTTP request. So, first things first: get the http protocol OutboundHTTPProtocol *pHTTP = (OutboundHTTPProtocol *) _pFarProtocol; //8. We wish to disconnect after the transfer is complete pHTTP->SetDisconnectAfterTransfer(true); //9. This will always be a POST pHTTP->Method(HTTP_METHOD_POST); //10. Our document and the host pHTTP->Document(variant["document"]); pHTTP->Host(variant["host"]); //11. Serialize it if (!Serialize(rawContent, variant["payload"])) { FATAL("Unable to serialize variant"); return false; } _outputBuffer.ReadFromString(rawContent); //12. enqueue for outbound return EnqueueForOutbound(); #else FATAL("HTTP protocol not supported"); return false; #endif /* HAS_PROTOCOL_HTTP */ } case PT_INBOUND_HTTP: { #ifdef HAS_PROTOCOL_HTTP if (!Serialize(rawContent, variant)) { FATAL("Unable to serialize variant"); return false; } _outputBuffer.ReadFromString(rawContent); return EnqueueForOutbound(); #else FATAL("HTTP protocol not supported"); return false; #endif /* HAS_PROTOCOL_HTTP */ } default: { ASSERT("We should not be here"); return false; } } }
bool InboundRTMPProtocol::PerformComplexHandshake(IOBuffer &buffer, bool encrypted) { //get the buffers uint8_t *pInputBuffer = GETIBPOINTER(buffer); if (_pOutputBuffer == NULL) { _pOutputBuffer = new uint8_t[3072]; } else { delete[] _pOutputBuffer; _pOutputBuffer = new uint8_t[3072]; } //timestamp EHTONLP(_pOutputBuffer, (uint32_t) time(NULL)); //version EHTONLP(_pOutputBuffer + 4, (uint32_t) 0x00000000); //generate random data for (uint32_t i = 8; i < 3072; i++) { _pOutputBuffer[i] = rand() % 256; } for (uint32_t i = 0; i < 10; i++) { uint32_t index = rand() % (3072 - HTTP_HEADERS_SERVER_US_LEN); memcpy(_pOutputBuffer + index, HTTP_HEADERS_SERVER_US, HTTP_HEADERS_SERVER_US_LEN); } //**** FIRST 1536 bytes from server response ****// //compute DH key position uint32_t serverDHOffset = GetDHOffset(_pOutputBuffer, _handshakeScheme); uint32_t clientDHOffset = GetDHOffset(pInputBuffer, _handshakeScheme); //generate DH key DHWrapper dhWrapper(1024); if (!dhWrapper.Initialize()) { FATAL("Unable to initialize DH wrapper"); return false; } if (!dhWrapper.CreateSharedKey(pInputBuffer + clientDHOffset, 128)) { FATAL("Unable to create shared key"); return false; } if (!dhWrapper.CopyPublicKey(_pOutputBuffer + serverDHOffset, 128)) { FATAL("Couldn't write public key!"); return false; } if (encrypted) { uint8_t secretKey[128]; if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) { FATAL("Unable to copy shared key"); return false; } _pKeyIn = new RC4_KEY; _pKeyOut = new RC4_KEY; InitRC4Encryption( secretKey, (uint8_t*) & pInputBuffer[clientDHOffset], (uint8_t*) & _pOutputBuffer[serverDHOffset], _pKeyIn, _pKeyOut); //bring the keys to correct cursor uint8_t data[1536]; RC4(_pKeyIn, 1536, data, data); RC4(_pKeyOut, 1536, data, data); } //generate the digest uint32_t serverDigestOffset = GetDigestOffset(_pOutputBuffer, _handshakeScheme); uint8_t *pTempBuffer = new uint8_t[1536 - 32]; memcpy(pTempBuffer, _pOutputBuffer, serverDigestOffset); memcpy(pTempBuffer + serverDigestOffset, _pOutputBuffer + serverDigestOffset + 32, 1536 - serverDigestOffset - 32); uint8_t *pTempHash = new uint8_t[512]; HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash); //put the digest in place memcpy(_pOutputBuffer + serverDigestOffset, pTempHash, 32); //cleanup delete[] pTempBuffer; delete[] pTempHash; //**** SECOND 1536 bytes from server response ****// //Compute the chalange index from the initial client request uint32_t keyChallengeIndex = GetDigestOffset(pInputBuffer, _handshakeScheme); //compute the key pTempHash = new uint8_t[512]; HMACsha256(pInputBuffer + keyChallengeIndex, //pData 32, //dataLength BaseRTMPProtocol::genuineFMSKey, //key 68, //keyLength pTempHash //pResult ); //generate the hash uint8_t *pLastHash = new uint8_t[512]; HMACsha256(_pOutputBuffer + 1536, //pData 1536 - 32, //dataLength pTempHash, //key 32, //keyLength pLastHash //pResult ); //put the hash where it belongs memcpy(_pOutputBuffer + 1536 * 2 - 32, pLastHash, 32); //cleanup delete[] pTempHash; delete[] pLastHash; //***** DONE BUILDING THE RESPONSE ***// //wire the response if (encrypted) _outputBuffer.ReadFromByte(6); else _outputBuffer.ReadFromByte(3); _outputBuffer.ReadFromBuffer(_pOutputBuffer, 3072); //final cleanup delete[] _pOutputBuffer; _pOutputBuffer = NULL; if (!buffer.IgnoreAll()) { 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; }