Global cleanups and standardization of code style.

This commit is contained in:
Thulinma 2012-12-11 11:03:33 +01:00
parent 51a9b4162c
commit 38ef8704f8
33 changed files with 4322 additions and 2824 deletions

View file

@ -7,7 +7,7 @@
char versionstring[] = "WWW.DDVTECH.COM "; ///< String that is repeated in the RTMP handshake
std::string RTMPStream::handshake_in; ///< Input for the handshake.
std::string RTMPStream::handshake_out;///< Output for the handshake.
std::string RTMPStream::handshake_out; ///< Output for the handshake.
unsigned int RTMPStream::chunk_rec_max = 128;
unsigned int RTMPStream::chunk_snd_max = 128;
@ -39,19 +39,17 @@ std::map<unsigned int, RTMPStream::Chunk> RTMPStream::Chunk::lastrecv;
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
uint8_t genuineFMSKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, // Genuine Adobe Flash Media Server 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 68
uint8_t genuineFMSKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x4d, 0x65, 0x64, 0x69, 0x61, 0x20, 0x53, 0x65, 0x72,
0x76, // Genuine Adobe Flash Media Server 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 68
uint8_t genuineFPKey[] = {
0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x50, 0x6c, 0x61, 0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57,
0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae
}; // 62
uint8_t genuineFPKey[] = {0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x20,
0x50, 0x6c, 0x61,
0x79, // Genuine Adobe Flash Player 001
0x65, 0x72, 0x20, 0x30, 0x30, 0x31, 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, 0x6e, 0xec,
0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae}; // 62
inline uint32_t GetDigestOffset(uint8_t *pBuffer, uint8_t scheme){
if (scheme == 0){
@ -69,7 +67,7 @@ inline uint32_t GetDHOffset(uint8_t *pBuffer, uint8_t scheme){
}
}
class DHWrapper {
class DHWrapper{
private:
int32_t _bitsCount;
DH *_pDH;
@ -89,7 +87,7 @@ class DHWrapper {
bool CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength);
};
DHWrapper::DHWrapper(int32_t bitsCount) {
DHWrapper::DHWrapper(int32_t bitsCount){
_bitsCount = bitsCount;
_pDH = 0;
_pSharedKey = 0;
@ -97,119 +95,172 @@ DHWrapper::DHWrapper(int32_t bitsCount) {
_peerPublickey = 0;
}
DHWrapper::~DHWrapper() {
DHWrapper::~DHWrapper(){
Cleanup();
}
bool DHWrapper::Initialize() {
bool DHWrapper::Initialize(){
Cleanup();
_pDH = DH_new();
if (!_pDH){Cleanup(); return false;}
if ( !_pDH){
Cleanup();
return false;
}
_pDH->p = BN_new();
if (!_pDH->p){Cleanup(); return false;}
if ( !_pDH->p){
Cleanup();
return false;
}
_pDH->g = BN_new();
if (!_pDH->g){Cleanup(); return false;}
if (BN_hex2bn(&_pDH->p, P1024) == 0){Cleanup(); return false;}
if (BN_set_word(_pDH->g, 2) != 1){Cleanup(); return false;}
if ( !_pDH->g){
Cleanup();
return false;
}
if (BN_hex2bn( &_pDH->p, P1024) == 0){
Cleanup();
return false;
}
if (BN_set_word(_pDH->g, 2) != 1){
Cleanup();
return false;
}
_pDH->length = _bitsCount;
if (DH_generate_key(_pDH) != 1){Cleanup(); return false;}
if (DH_generate_key(_pDH) != 1){
Cleanup();
return false;
}
return true;
}
bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength) {
if (!_pDH){return false;}
bool DHWrapper::CopyPublicKey(uint8_t *pDst, int32_t dstLength){
if ( !_pDH){
return false;
}
return CopyKey(_pDH->pub_key, pDst, dstLength);
}
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength) {
if (!_pDH){return false;}
bool DHWrapper::CopyPrivateKey(uint8_t *pDst, int32_t dstLength){
if ( !_pDH){
return false;
}
return CopyKey(_pDH->priv_key, pDst, dstLength);
}
bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length) {
if (!_pDH){return false;}
if (_sharedKeyLength != 0 || _pSharedKey){return false;}
bool DHWrapper::CreateSharedKey(uint8_t *pPeerPublicKey, int32_t length){
if ( !_pDH){
return false;
}
if (_sharedKeyLength != 0 || _pSharedKey){
return false;
}
_sharedKeyLength = DH_size(_pDH);
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){return false;}
if (_sharedKeyLength <= 0 || _sharedKeyLength > 1024){
return false;
}
_pSharedKey = new uint8_t[_sharedKeyLength];
_peerPublickey = BN_bin2bn(pPeerPublicKey, length, 0);
if (!_peerPublickey){return false;}
if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){return false;}
if ( !_peerPublickey){
return false;
}
if (DH_compute_key(_pSharedKey, _peerPublickey, _pDH) != _sharedKeyLength){
return false;
}
return true;
}
bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength) {
if (!_pDH){return false;}
if (dstLength != _sharedKeyLength){return false;}
bool DHWrapper::CopySharedKey(uint8_t *pDst, int32_t dstLength){
if ( !_pDH){
return false;
}
if (dstLength != _sharedKeyLength){
return false;
}
memcpy(pDst, _pSharedKey, _sharedKeyLength);
return true;
}
void DHWrapper::Cleanup() {
void DHWrapper::Cleanup(){
if (_pDH){
if (_pDH->p){BN_free(_pDH->p); _pDH->p = 0;}
if (_pDH->g){BN_free(_pDH->g); _pDH->g = 0;}
DH_free(_pDH); _pDH = 0;
if (_pDH->p){
BN_free(_pDH->p);
_pDH->p = 0;
}
if (_pDH->g){
BN_free(_pDH->g);
_pDH->g = 0;
}
DH_free(_pDH);
_pDH = 0;
}
if (_pSharedKey){
delete[] _pSharedKey;
_pSharedKey = 0;
}
if (_pSharedKey){delete[] _pSharedKey; _pSharedKey = 0;}
_sharedKeyLength = 0;
if (_peerPublickey){BN_free(_peerPublickey); _peerPublickey = 0;}
if (_peerPublickey){
BN_free(_peerPublickey);
_peerPublickey = 0;
}
}
bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength) {
bool DHWrapper::CopyKey(BIGNUM *pNum, uint8_t *pDst, int32_t dstLength){
int32_t keySize = BN_num_bytes(pNum);
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){return false;}
if (BN_bn2bin(pNum, pDst) != keySize){return false;}
if ((keySize <= 0) || (dstLength <= 0) || (keySize > dstLength)){
return false;
}
if (BN_bn2bin(pNum, pDst) != keySize){
return false;
}
return true;
}
void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut) {
void InitRC4Encryption(uint8_t *secretKey, uint8_t *pubKeyIn, uint8_t *pubKeyOut, RC4_KEY *rc4keyIn, RC4_KEY *rc4keyOut){
uint8_t digest[SHA256_DIGEST_LENGTH];
unsigned int digestLen = 0;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
HMAC_Update(&ctx, pubKeyIn, 128);
HMAC_Final(&ctx, digest, &digestLen);
HMAC_CTX_cleanup(&ctx);
HMAC_CTX_init( &ctx);
HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0);
HMAC_Update( &ctx, pubKeyIn, 128);
HMAC_Final( &ctx, digest, &digestLen);
HMAC_CTX_cleanup( &ctx);
RC4_set_key(rc4keyOut, 16, digest);
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, secretKey, 128, EVP_sha256(), 0);
HMAC_Update(&ctx, pubKeyOut, 128);
HMAC_Final(&ctx, digest, &digestLen);
HMAC_CTX_cleanup(&ctx);
HMAC_CTX_init( &ctx);
HMAC_Init_ex( &ctx, secretKey, 128, EVP_sha256(), 0);
HMAC_Update( &ctx, pubKeyOut, 128);
HMAC_Final( &ctx, digest, &digestLen);
HMAC_CTX_cleanup( &ctx);
RC4_set_key(rc4keyIn, 16, digest);
}
void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult) {
void HMACsha256(const void *pData, uint32_t dataLength, const void *pKey, uint32_t keyLength, void *pResult){
unsigned int digestLen;
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, (unsigned char*) pKey, keyLength, EVP_sha256(), 0);
HMAC_Update(&ctx, (unsigned char *) pData, dataLength);
HMAC_Final(&ctx, (unsigned char *) pResult, &digestLen);
HMAC_CTX_cleanup(&ctx);
HMAC_CTX_init( &ctx);
HMAC_Init_ex( &ctx, (unsigned char*)pKey, keyLength, EVP_sha256(), 0);
HMAC_Update( &ctx, (unsigned char *)pData, dataLength);
HMAC_Final( &ctx, (unsigned char *)pResult, &digestLen);
HMAC_CTX_cleanup( &ctx);
}
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme) {
bool ValidateClientScheme(uint8_t * pBuffer, uint8_t scheme){
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 = (memcmp(pBuffer+clientDigestOffset, pTempHash, 32) == 0);
#if DEBUG >= 4
bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
#if DEBUG >= 4
fprintf(stderr, "Client scheme validation %hhi %s\n", scheme, result?"success":"failed");
#endif
#endif
delete[] pTempBuffer;
delete[] pTempHash;
return result;
@ -226,23 +277,25 @@ std::string & RTMPStream::Chunk::Pack(){
unsigned char chtype = 0x00;
if ((prev.msg_type_id > 0) && (prev.cs_id == cs_id)){
if (msg_stream_id == prev.msg_stream_id){
chtype = 0x40;//do not send msg_stream_id
chtype = 0x40; //do not send msg_stream_id
if (len == prev.len){
if (msg_type_id == prev.msg_type_id){
chtype = 0x80;//do not send len and msg_type_id
chtype = 0x80; //do not send len and msg_type_id
if (timestamp == prev.timestamp){
chtype = 0xC0;//do not send timestamp
chtype = 0xC0; //do not send timestamp
}
}
}
}
//override - we always sent type 0x00 if the timestamp has decreased since last chunk in this channel
if (timestamp < prev.timestamp){chtype = 0x00;}
if (timestamp < prev.timestamp){
chtype = 0x00;
}
}
if (cs_id <= 63){
output += (unsigned char)(chtype | cs_id);
}else{
if (cs_id <= 255+64){
if (cs_id <= 255 + 64){
output += (unsigned char)(chtype | 0);
output += (unsigned char)(cs_id - 64);
}else{
@ -259,7 +312,10 @@ std::string & RTMPStream::Chunk::Pack(){
}else{
tmpi = timestamp - prev.timestamp;
}
if (tmpi >= 0x00ffffff){ntime = tmpi; tmpi = 0x00ffffff;}
if (tmpi >= 0x00ffffff){
ntime = tmpi;
tmpi = 0x00ffffff;
}
output += (unsigned char)((tmpi >> 16) & 0xff);
output += (unsigned char)((tmpi >> 8) & 0xff);
output += (unsigned char)(tmpi & 0xff);
@ -275,8 +331,8 @@ std::string & RTMPStream::Chunk::Pack(){
//msg stream id
output += (unsigned char)(msg_stream_id % 256);
output += (unsigned char)(msg_stream_id / 256);
output += (unsigned char)(msg_stream_id / (256*256));
output += (unsigned char)(msg_stream_id / (256*256*256));
output += (unsigned char)(msg_stream_id / (256 * 256));
output += (unsigned char)(msg_stream_id / (256 * 256 * 256));
}
}
}
@ -290,14 +346,16 @@ std::string & RTMPStream::Chunk::Pack(){
len_left = 0;
while (len_left < len){
tmpi = len - len_left;
if (tmpi > RTMPStream::chunk_snd_max){tmpi = RTMPStream::chunk_snd_max;}
if (tmpi > RTMPStream::chunk_snd_max){
tmpi = RTMPStream::chunk_snd_max;
}
output.append(data, len_left, tmpi);
len_left += tmpi;
if (len_left < len){
if (cs_id <= 63){
output += (unsigned char)(0xC0 + cs_id);
}else{
if (cs_id <= 255+64){
if (cs_id <= 255 + 64){
output += (unsigned char)(0xC0);
output += (unsigned char)(cs_id - 64);
}else{
@ -311,10 +369,11 @@ std::string & RTMPStream::Chunk::Pack(){
lastsend[cs_id] = *this;
RTMPStream::snd_cnt += output.size();
return output;
}//SendChunk
} //SendChunk
/// Default contructor, creates an empty chunk with all values initialized to zero.
/// Default constructor, creates an empty chunk with all values initialized to zero.
RTMPStream::Chunk::Chunk(){
headertype = 0;
cs_id = 0;
timestamp = 0;
len = 0;
@ -323,7 +382,7 @@ RTMPStream::Chunk::Chunk(){
msg_type_id = 0;
msg_stream_id = 0;
data = "";
}//constructor
} //constructor
/// Packs up a chunk with the given arguments as properties.
std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_id, unsigned int msg_stream_id, std::string data){
@ -337,7 +396,7 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i
ch.msg_stream_id = msg_stream_id;
ch.data = data;
return ch.Pack();
}//constructor
} //constructor
/// Packs up a chunk with media contents.
/// \param msg_type_id Type number of the media, as per FLV standard.
@ -346,7 +405,7 @@ std::string & RTMPStream::SendChunk(unsigned int cs_id, unsigned char msg_type_i
/// \param ts Timestamp of the media data, relative to current system time.
std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * data, int len, unsigned int ts){
static RTMPStream::Chunk ch;
ch.cs_id = msg_type_id+42;
ch.cs_id = msg_type_id + 42;
ch.timestamp = ts;
ch.len = len;
ch.real_len = len;
@ -355,7 +414,7 @@ std::string & RTMPStream::SendMedia(unsigned char msg_type_id, unsigned char * d
ch.msg_stream_id = 1;
ch.data = std::string((char*)data, (size_t)len);
return ch.Pack();
}//SendMedia
} //SendMedia
/// Packs up a chunk with media contents.
/// \param tag FLV::Tag with media to send.
@ -363,14 +422,14 @@ std::string & RTMPStream::SendMedia(FLV::Tag & tag){
static RTMPStream::Chunk ch;
ch.cs_id = ((unsigned char)tag.data[0]);
ch.timestamp = tag.tagTime();
ch.len = tag.len-15;
ch.real_len = tag.len-15;
ch.len = tag.len - 15;
ch.real_len = tag.len - 15;
ch.len_left = 0;
ch.msg_type_id = (unsigned char)tag.data[0];
ch.msg_stream_id = 1;
ch.data = std::string(tag.data+11, (size_t)(tag.len-15));
ch.data = std::string(tag.data + 11, (size_t)(tag.len - 15));
return ch.Pack();
}//SendMedia
} //SendMedia
/// Packs up a chunk for a control message with 1 argument.
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){
@ -385,7 +444,7 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data){
ch.data.resize(4);
*(int*)((char*)ch.data.c_str()) = htonl(data);
return ch.Pack();
}//SendCTL
} //SendCTL
/// Packs up a chunk for a control message with 2 arguments.
std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigned char data2){
@ -401,7 +460,7 @@ std::string & RTMPStream::SendCTL(unsigned char type, unsigned int data, unsigne
*(unsigned int*)((char*)ch.data.c_str()) = htonl(data);
ch.data[4] = data2;
return ch.Pack();
}//SendCTL
} //SendCTL
/// Packs up a chunk for a user control message with 1 argument.
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){
@ -414,11 +473,11 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data){
ch.msg_type_id = 4;
ch.msg_stream_id = 0;
ch.data.resize(6);
*(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data);
*(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data);
ch.data[0] = 0;
ch.data[1] = type;
return ch.Pack();
}//SendUSR
} //SendUSR
/// Packs up a chunk for a user control message with 2 arguments.
std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigned int data2){
@ -431,13 +490,12 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
ch.msg_type_id = 4;
ch.msg_stream_id = 0;
ch.data.resize(10);
*(unsigned int*)(((char*)ch.data.c_str())+2) = htonl(data);
*(unsigned int*)(((char*)ch.data.c_str())+6) = htonl(data2);
*(unsigned int*)(((char*)ch.data.c_str()) + 2) = htonl(data);
*(unsigned int*)(((char*)ch.data.c_str()) + 6) = htonl(data2);
ch.data[0] = 0;
ch.data[1] = type;
return ch.Pack();
}//SendUSR
} //SendUSR
/// Parses the argument string into the current chunk.
/// Tries to read a whole chunk, removing data from the input string as it reads.
@ -448,21 +506,21 @@ std::string & RTMPStream::SendUSR(unsigned char type, unsigned int data, unsigne
/// \warning This function will destroy the current data in this chunk!
/// \returns True if a whole chunk could be read, false otherwise.
bool RTMPStream::Chunk::Parse(std::string & indata){
gettimeofday(&RTMPStream::lastrec, 0);
gettimeofday( &RTMPStream::lastrec, 0);
unsigned int i = 0;
if (indata.size() < 1) return false;//need at least a byte
if (indata.size() < 1) return false; //need at least a byte
unsigned char chunktype = indata[i++];
unsigned char chunktype = indata[i++ ];
//read the chunkstream ID properly
switch (chunktype & 0x3F){
case 0:
if (indata.size() < 2) return false;//need at least 2 bytes to continue
cs_id = indata[i++] + 64;
if (indata.size() < 2) return false; //need at least 2 bytes to continue
cs_id = indata[i++ ] + 64;
break;
case 1:
if (indata.size() < 3) return false;//need at least 3 bytes to continue
cs_id = indata[i++] + 64;
cs_id += indata[i++] * 256;
if (indata.size() < 3) return false; //need at least 3 bytes to continue
cs_id = indata[i++ ] + 64;
cs_id += indata[i++ ] * 256;
break;
default:
cs_id = chunktype & 0x3F;
@ -475,48 +533,58 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
headertype = chunktype & 0xC0;
switch (headertype){
case 0x00:
if (indata.size() < i+11) return false; //can't read whole header
timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
len = indata[i++]*256*256;
len += indata[i++]*256;
len += indata[i++];
if (indata.size() < i + 11) return false; //can't read whole header
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
len = indata[i++ ] * 256 * 256;
len += indata[i++ ] * 256;
len += indata[i++ ];
len_left = 0;
msg_type_id = indata[i++];
msg_stream_id = indata[i++];
msg_stream_id += indata[i++]*256;
msg_stream_id += indata[i++]*256*256;
msg_stream_id += indata[i++]*256*256*256;
msg_type_id = indata[i++ ];
msg_stream_id = indata[i++ ];
msg_stream_id += indata[i++ ] * 256;
msg_stream_id += indata[i++ ] * 256 * 256;
msg_stream_id += indata[i++ ] * 256 * 256 * 256;
break;
case 0x40:
if (indata.size() < i+7) return false; //can't read whole header
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");}
timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
len = indata[i++]*256*256;
len += indata[i++]*256;
len += indata[i++];
if (indata.size() < i + 7) return false; //can't read whole header
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = indata[i++ ] * 256 * 256;
len += indata[i++ ] * 256;
len += indata[i++ ];
len_left = 0;
msg_type_id = indata[i++];
msg_type_id = indata[i++ ];
msg_stream_id = prev.msg_stream_id;
break;
case 0x80:
if (indata.size() < i+3) return false; //can't read whole header
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");}
timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
if (indata.size() < i + 3) return false; //can't read whole header
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = prev.len;
len_left = prev.len_left;
msg_type_id = prev.msg_type_id;
msg_stream_id = prev.msg_stream_id;
break;
case 0xC0:
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");
}
timestamp = prev.timestamp;
len = prev.len;
len_left = prev.len_left;
@ -537,11 +605,11 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
}
//read extended timestamp, if neccesary
if (timestamp == 0x00ffffff){
if (indata.size() < i+4) return false; //can't read whole header
timestamp = indata[i++]*256*256*256;
timestamp += indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
if (indata.size() < i + 4) return false; //can't read whole header
timestamp = indata[i++ ] * 256 * 256 * 256;
timestamp += indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
}
//read data if length > 0, and allocate it
@ -551,11 +619,11 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
}else{
data = "";
}
if (indata.size() < i+real_len) return false;//can't read all data (yet)
if (indata.size() < i + real_len) return false; //can't read all data (yet)
data.append(indata, i, real_len);
indata = indata.substr(i+real_len);
indata = indata.substr(i + real_len);
lastrecv[cs_id] = *this;
RTMPStream::rec_cnt += i+real_len;
RTMPStream::rec_cnt += i + real_len;
if (len_left == 0){
return true;
}else{
@ -563,12 +631,12 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
}
}else{
data = "";
indata = indata.substr(i+real_len);
indata = indata.substr(i + real_len);
lastrecv[cs_id] = *this;
RTMPStream::rec_cnt += i+real_len;
RTMPStream::rec_cnt += i + real_len;
return true;
}
}//Parse
} //Parse
/// Parses the argument string into the current chunk.
/// Tries to read a whole chunk, removing data from the input as it reads.
@ -579,77 +647,95 @@ bool RTMPStream::Chunk::Parse(std::string & indata){
/// \warning This function will destroy the current data in this chunk!
/// \returns True if a whole chunk could be read, false otherwise.
bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
gettimeofday(&RTMPStream::lastrec, 0);
gettimeofday( &RTMPStream::lastrec, 0);
unsigned int i = 0;
if (!buffer.available(3)){return false;}//we want at least 3 bytes
if ( !buffer.available(3)){
return false;
} //we want at least 3 bytes
std::string indata = buffer.copy(3);
unsigned char chunktype = indata[i++];
unsigned char chunktype = indata[i++ ];
//read the chunkstream ID properly
switch (chunktype & 0x3F){
case 0:
cs_id = indata[i++] + 64;
cs_id = indata[i++ ] + 64;
break;
case 1:
cs_id = indata[i++] + 64;
cs_id += indata[i++] * 256;
cs_id = indata[i++ ] + 64;
cs_id += indata[i++ ] * 256;
break;
default:
cs_id = chunktype & 0x3F;
break;
}
RTMPStream::Chunk prev = lastrecv[cs_id];
//process the rest of the header, for each chunk type
headertype = chunktype & 0xC0;
switch (headertype){
case 0x00:
if (!buffer.available(i+11)){return false;} //can't read whole header
indata = buffer.copy(i+11);
timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
len = indata[i++]*256*256;
len += indata[i++]*256;
len += indata[i++];
if ( !buffer.available(i + 11)){
return false;
} //can't read whole header
indata = buffer.copy(i + 11);
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
len = indata[i++ ] * 256 * 256;
len += indata[i++ ] * 256;
len += indata[i++ ];
len_left = 0;
msg_type_id = indata[i++];
msg_stream_id = indata[i++];
msg_stream_id += indata[i++]*256;
msg_stream_id += indata[i++]*256*256;
msg_stream_id += indata[i++]*256*256*256;
msg_type_id = indata[i++ ];
msg_stream_id = indata[i++ ];
msg_stream_id += indata[i++ ] * 256;
msg_stream_id += indata[i++ ] * 256 * 256;
msg_stream_id += indata[i++ ] * 256 * 256 * 256;
break;
case 0x40:
if (!buffer.available(i+7)){return false;} //can't read whole header
indata = buffer.copy(i+7);
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");}
timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
len = indata[i++]*256*256;
len += indata[i++]*256;
len += indata[i++];
if ( !buffer.available(i + 7)){
return false;
} //can't read whole header
indata = buffer.copy(i + 7);
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x40 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = indata[i++ ] * 256 * 256;
len += indata[i++ ] * 256;
len += indata[i++ ];
len_left = 0;
msg_type_id = indata[i++];
msg_type_id = indata[i++ ];
msg_stream_id = prev.msg_stream_id;
break;
case 0x80:
if (!buffer.available(i+3)){return false;} //can't read whole header
indata = buffer.copy(i+3);
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");}
timestamp = indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
if (timestamp != 0x00ffffff){timestamp += prev.timestamp;}
if ( !buffer.available(i + 3)){
return false;
} //can't read whole header
indata = buffer.copy(i + 3);
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0x80 with no valid previous chunk!\n");
}
timestamp = indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
if (timestamp != 0x00ffffff){
timestamp += prev.timestamp;
}
len = prev.len;
len_left = prev.len_left;
msg_type_id = prev.msg_type_id;
msg_stream_id = prev.msg_stream_id;
break;
case 0xC0:
if (prev.msg_type_id == 0){fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");}
if (prev.msg_type_id == 0){
fprintf(stderr, "Warning: Header type 0xC0 with no valid previous chunk!\n");
}
timestamp = prev.timestamp;
len = prev.len;
len_left = prev.len_left;
@ -670,39 +756,43 @@ bool RTMPStream::Chunk::Parse(Socket::Buffer & buffer){
}
//read extended timestamp, if neccesary
if (timestamp == 0x00ffffff){
if (!buffer.available(i+4)){return false;} //can't read timestamp
indata = buffer.copy(i+4);
timestamp = indata[i++]*256*256*256;
timestamp += indata[i++]*256*256;
timestamp += indata[i++]*256;
timestamp += indata[i++];
if ( !buffer.available(i + 4)){
return false;
} //can't read timestamp
indata = buffer.copy(i + 4);
timestamp = indata[i++ ] * 256 * 256 * 256;
timestamp += indata[i++ ] * 256 * 256;
timestamp += indata[i++ ] * 256;
timestamp += indata[i++ ];
}
//read data if length > 0, and allocate it
if (real_len > 0){
if (!buffer.available(i+real_len)){return false;}//can't read all data (yet)
buffer.remove(i);//remove the header
if ( !buffer.available(i + real_len)){
return false;
} //can't read all data (yet)
buffer.remove(i); //remove the header
if (prev.len_left > 0){
data = prev.data + buffer.remove(real_len);//append the data and remove from buffer
data = prev.data + buffer.remove(real_len); //append the data and remove from buffer
}else{
data = buffer.remove(real_len);//append the data and remove from buffer
data = buffer.remove(real_len); //append the data and remove from buffer
}
lastrecv[cs_id] = *this;
RTMPStream::rec_cnt += i+real_len;
RTMPStream::rec_cnt += i + real_len;
if (len_left == 0){
return true;
}else{
return Parse(buffer);
}
}else{
buffer.remove(i);//remove the header
buffer.remove(i); //remove the header
data = "";
indata = indata.substr(i+real_len);
indata = indata.substr(i + real_len);
lastrecv[cs_id] = *this;
RTMPStream::rec_cnt += i+real_len;
RTMPStream::rec_cnt += i + real_len;
return true;
}
}//Parse
} //Parse
/// Does the handshake. Expects handshake_in to be filled, and fills handshake_out.
/// After calling this function, don't forget to read and ignore 1536 extra bytes,
@ -718,21 +808,23 @@ bool RTMPStream::doHandshake(){
RTMPStream::rec_cnt += 1537;
//Build S1 Packet
*((uint32_t*)Server) = 0;//time zero
*(((uint32_t*)(Server+4))) = htonl(0x01020304);//version 1 2 3 4
for (int i = 8; i < 3072; ++i){Server[i] = versionstring[i%16];}//"random" data
*((uint32_t*)Server) = 0; //time zero
*(((uint32_t*)(Server + 4))) = htonl(0x01020304); //version 1 2 3 4
for (int i = 8; i < 3072; ++i){
Server[i] = versionstring[i % 16];
} //"random" data
bool encrypted = (Version == 6);
#if DEBUG >= 4
#if DEBUG >= 4
fprintf(stderr, "Handshake version is %hhi\n", Version);
#endif
#endif
uint8_t _validationScheme = 5;
if (ValidateClientScheme(Client, 0)) _validationScheme = 0;
if (ValidateClientScheme(Client, 1)) _validationScheme = 1;
#if DEBUG >= 4
#if DEBUG >= 4
fprintf(stderr, "Handshake type is %hhi, encryption is %s\n", _validationScheme, encrypted?"on":"off");
#endif
#endif
//FIRST 1536 bytes from server response
//compute DH key position
@ -741,19 +833,19 @@ bool RTMPStream::doHandshake(){
//generate DH key
DHWrapper dhWrapper(1024);
if (!dhWrapper.Initialize()) return false;
if (!dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) return false;
if (!dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) return false;
if ( !dhWrapper.Initialize()) return false;
if ( !dhWrapper.CreateSharedKey(Client + clientDHOffset, 128)) return false;
if ( !dhWrapper.CopyPublicKey(Server + serverDHOffset, 128)) return false;
if (encrypted) {
if (encrypted){
uint8_t secretKey[128];
if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) return false;
if ( !dhWrapper.CopySharedKey(secretKey, sizeof(secretKey))) return false;
RC4_KEY _pKeyIn;
RC4_KEY _pKeyOut;
InitRC4Encryption(secretKey, (uint8_t*) & Client[clientDHOffset], (uint8_t*) & Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
InitRC4Encryption(secretKey, (uint8_t*) &Client[clientDHOffset], (uint8_t*) &Server[serverDHOffset], &_pKeyIn, &_pKeyOut);
uint8_t data[1536];
RC4(&_pKeyIn, 1536, data, data);
RC4(&_pKeyOut, 1536, data, data);
RC4( &_pKeyIn, 1536, data, data);
RC4( &_pKeyOut, 1536, data, data);
}
//generate the digest
uint32_t serverDigestOffset = GetDigestOffset(Server, _validationScheme);
@ -776,7 +868,7 @@ bool RTMPStream::doHandshake(){
delete[] pTempHash;
delete[] pLastHash;
//DONE BUILDING THE RESPONSE ***//
Server[-1] = Version;
Server[ -1] = Version;
RTMPStream::snd_cnt += 3073;
return true;
}