Global cleanups and standardization of code style.
This commit is contained in:
parent
51a9b4162c
commit
38ef8704f8
33 changed files with 4322 additions and 2824 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue