生活随笔
收集整理的這篇文章主要介紹了
RTMPdump(libRTMP)源代码分析 4: 连接第一步——握手(Hand Shake)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
=====================================================
RTMPdump(libRTMP) 源代碼分析系列文章:
RTMPdump 源代碼分析?1: main()函數(shù)
RTMPDump (libRTMP) 源代碼分析2:解析RTMP地址——RTMP_ParseURL()
RTMPdump (libRTMP) 源代碼分析3: AMF編碼
RTMPdump (libRTMP) 源代碼分析4: 連接第一步——握手 (HandShake)
RTMPdump (libRTMP) 源代碼分析5: 建立一個(gè)流媒體連接 ?(NetConnection部分)
RTMPdump (libRTMP) 源代碼分析6: 建立一個(gè)流媒體連接 ?(NetStream部分 1)
RTMPdump (libRTMP) 源代碼分析7: 建立一個(gè)流媒體連接 ?(NetStream部分 2)
RTMPdump (libRTMP) 源代碼分析8: 發(fā)送消息 (Message)
RTMPdump (libRTMP) 源代碼分析9: 接收消息 (Message) ?(接收視音頻數(shù)據(jù))
RTMPdump (libRTMP) 源代碼分析10: 處理各種消息 (Message)
=====================================================
函數(shù)調(diào)用結(jié)構(gòu)圖
RTMPDump (libRTMP)的整體的函數(shù)調(diào)用結(jié)構(gòu)圖如下圖所示。
單擊查看大圖
詳細(xì)分析
在這里分析一下RTMPdump(libRTMP)連接到支持RTMP協(xié)議的服務(wù)器的第一步:握手(Hand Shake)。
RTMP連接的過程曾經(jīng)分析過:RTMP流媒體播放過程
在這里不再細(xì)說,分析一下位于handshake.h文件里面實(shí)現(xiàn)握手(HandShake)功能的函數(shù):
注意:handshake.h里面代碼量很大,但是很多代碼都是為了處理RTMP的加密版協(xié)議的,例如rtmps;因此在這里就不做過多分析了,我們只考慮普通的RTMP協(xié)議。
[cpp]?view plaincopy
static?int?? HandShake(RTMP?*?r,?int?FP9HandShake)?? {?? ??int?i,?offalg?=?0;?? ??int?dhposClient?=?0;?? ??int?digestPosClient?=?0;?? ??int?encrypted?=?r->Link.protocol?&?RTMP_FEATURE_ENC;?? ?? ??RC4_handle?keyIn?=?0;?? ??RC4_handle?keyOut?=?0;?? ?? ??int32_t?*ip;?? ??uint32_t?uptime;?? ?? ??uint8_t?clientbuf[RTMP_SIG_SIZE?+?4],?*clientsig=clientbuf+4;?? ??uint8_t?serversig[RTMP_SIG_SIZE],?client2[RTMP_SIG_SIZE],?*reply;?? ??uint8_t?type;?? ??getoff?*getdh?=?NULL,?*getdig?=?NULL;?? ?? ??if?(encrypted?||?r->Link.SWFSize)?? ????FP9HandShake?=?TRUE;?? ??else?? ?????? ????FP9HandShake?=?FALSE;?? ?? ??r->Link.rc4keyIn?=?r->Link.rc4keyOut?=?0;?? ?? ??if?(encrypted)?? ????{?? ??????clientsig[-1]?=?0x06;??? ??????offalg?=?1;?? ????}?? ??else?? ?????? ?????? ?????? ????clientsig[-1]?=?0x03;?? ?? ??uptime?=?htonl(RTMP_GetTime());?? ???? ???? ???? ???? ??memcpy(clientsig,?&uptime,?4);?? ?? ??if?(FP9HandShake)?? ????{?? ???????? ??????if?(encrypted)?? ????{?? ??????clientsig[4]?=?128;?? ??????clientsig[6]?=?3;?? ????}?? ??????else?? ????????{?? ??????clientsig[4]?=?10;?? ??????clientsig[6]?=?45;?? ????}?? ??????clientsig[5]?=?0;?? ??????clientsig[7]?=?2;?? ?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Client?type:?%02X",?__FUNCTION__,?clientsig[-1]);?? ??????getdig?=?digoff[offalg];?? ??????getdh??=?dhoff[offalg];?? ????}?? ??else?? ????{?? ?????? ?????? ?????? ??????memset(&clientsig[4],?0,?4);?? ????}?? ?? ???? #ifdef?_DEBUG?? ???? ???? ??memset(clientsig+8,?0,?RTMP_SIG_SIZE-8);?? #else?? ???? ??ip?=?(int32_t?*)(clientsig+8);?? ??for?(i?=?2;?i?<?RTMP_SIG_SIZE/4;?i++)?? ????*ip++?=?rand();?? #endif?? ?? ???? ??if?(FP9HandShake)?? ????{?? ??????if?(encrypted)?? ????{?? ???????? ??????r->Link.dh?=?DHInit(1024);?? ??????if?(!r->Link.dh)?? ????????{?? ??????????RTMP_Log(RTMP_LOGERROR,?"%s:?Couldn't?initialize?Diffie-Hellmann!",?? ??????????__FUNCTION__);?? ??????????return?FALSE;?? ????????}?? ?? ??????dhposClient?=?getdh(clientsig,?RTMP_SIG_SIZE);?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?DH?pubkey?position:?%d",?__FUNCTION__,?dhposClient);?? ?? ??????if?(!DHGenerateKey((DH?*)r->Link.dh))?? ????????{?? ??????????RTMP_Log(RTMP_LOGERROR,?"%s:?Couldn't?generate?Diffie-Hellmann?public?key!",?? ??????????__FUNCTION__);?? ??????????return?FALSE;?? ????????}?? ?? ??????if?(!DHGetPublicKey((DH?*)r->Link.dh,?&clientsig[dhposClient],?128))?? ????????{?? ??????????RTMP_Log(RTMP_LOGERROR,?"%s:?Couldn't?write?public?key!",?__FUNCTION__);?? ??????????return?FALSE;?? ????????}?? ????}?? ?? ??????digestPosClient?=?getdig(clientsig,?RTMP_SIG_SIZE);????? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Client?digest?offset:?%d",?__FUNCTION__,?? ??????digestPosClient);?? ?? ??????CalculateDigest(digestPosClient,?clientsig,?GenuineFPKey,?30,?? ??????????????&clientsig[digestPosClient]);?? ?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Initial?client?digest:?",?__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?clientsig?+?digestPosClient,?? ?????????SHA256_DIGEST_LENGTH);?? ????}?? ?? #ifdef?_DEBUG?? ??RTMP_Log(RTMP_LOGDEBUG,?"Clientsig:?");?? ??RTMP_LogHex(RTMP_LOGDEBUG,?clientsig,?RTMP_SIG_SIZE);?? #endif?? ???? ???? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。發(fā)送握手?jǐn)?shù)據(jù)C0+C1");?? ???? ??if?(!WriteN(r,?(char?*)clientsig-1,?RTMP_SIG_SIZE?+?1))?? ????return?FALSE;?? ???? ???? ??if?(ReadN(r,?(char?*)&type,?1)?!=?1)???? ????return?FALSE;?? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。接收握手?jǐn)?shù)據(jù)S0");?? ???? ??RTMP_Log(RTMP_LOGDEBUG,?"%s:?Type?Answer???:?%02X",?__FUNCTION__,?type);?? ???? ??if?(type?!=?clientsig[-1])?? ????RTMP_Log(RTMP_LOGWARNING,?"%s:?Type?mismatch:?client?sent?%d,?server?answered?%d",?? ????__FUNCTION__,?clientsig[-1],?type);?? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。成功接收握手?jǐn)?shù)據(jù)S0,服務(wù)器和客戶端版本相同");?? ???? ???? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。接收握手?jǐn)?shù)據(jù)S1");?? ???? ??if?(ReadN(r,?(char?*)serversig,?RTMP_SIG_SIZE)?!=?RTMP_SIG_SIZE)?? ????return?FALSE;?? ?? ???? ???? ??memcpy(&uptime,?serversig,?4);?? ???? ??uptime?=?ntohl(uptime);?? ?? ??RTMP_Log(RTMP_LOGDEBUG,?"%s:?Server?Uptime?:?%d",?__FUNCTION__,?uptime);?? ??RTMP_Log(RTMP_LOGDEBUG,?"%s:?FMS?Version???:?%d.%d.%d.%d",?__FUNCTION__,?serversig[4],?? ??????serversig[5],?serversig[6],?serversig[7]);?? ?? ??if?(FP9HandShake?&&?type?==?3?&&?!serversig[4])?? ????FP9HandShake?=?FALSE;?? ?? #ifdef?_DEBUG?? ??RTMP_Log(RTMP_LOGDEBUG,?"Server?signature:");?? ??RTMP_LogHex(RTMP_LOGDEBUG,?serversig,?RTMP_SIG_SIZE);?? #endif?? ?? ??if?(FP9HandShake)?? ????{?? ??????uint8_t?digestResp[SHA256_DIGEST_LENGTH];?? ??????uint8_t?*signatureResp?=?NULL;?? ?? ???????? ??????int?digestPosServer?=?getdig(serversig,?RTMP_SIG_SIZE);?? ?? ??????if?(!VerifyDigest(digestPosServer,?serversig,?GenuineFMSKey,?36))?? ????{?? ??????RTMP_Log(RTMP_LOGWARNING,?"Trying?different?position?for?server?digest!");?? ??????offalg?^=?1;?? ??????getdig?=?digoff[offalg];?? ??????getdh??=?dhoff[offalg];?? ??????digestPosServer?=?getdig(serversig,?RTMP_SIG_SIZE);?? ?? ??????if?(!VerifyDigest(digestPosServer,?serversig,?GenuineFMSKey,?36))?? ????????{?? ??????????RTMP_Log(RTMP_LOGERROR,?"Couldn't?verify?the?server?digest");??? ??????????return?FALSE;?? ????????}?? ????}?? ?? ???????? ??????if?(r->Link.SWFSize)?? ????{?? ??????const?char?swfVerify[]?=?{?0x01,?0x01?};?? ??????char?*vend?=?r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);?? ?? ??????memcpy(r->Link.SWFVerificationResponse,?swfVerify,?2);?? ??????AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2],?vend,?r->Link.SWFSize);?? ??????AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6],?vend,?r->Link.SWFSize);?? ??????HMACsha256(r->Link.SWFHash,?SHA256_DIGEST_LENGTH,?? ?????????????&serversig[RTMP_SIG_SIZE?-?SHA256_DIGEST_LENGTH],?? ?????????????SHA256_DIGEST_LENGTH,?? ?????????????(uint8_t?*)&r->Link.SWFVerificationResponse[10]);?? ????}?? ?? ???????? ??????if?(encrypted)?? ????{?? ???????? ??????uint8_t?secretKey[128]?=?{?0?};?? ??????int?len,?dhposServer;?? ?? ??????dhposServer?=?getdh(serversig,?RTMP_SIG_SIZE);?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Server?DH?public?key?offset:?%d",?__FUNCTION__,?? ????????dhposServer);?? ??????len?=?DHComputeSharedSecretKey((DH?*)r->Link.dh,?&serversig[dhposServer],?? ????????????????????128,?secretKey);?? ??????if?(len?<?0)?? ????????{?? ??????????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Wrong?secret?key?position!",?__FUNCTION__);?? ??????????return?FALSE;?? ????????}?? ?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Secret?key:?",?__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?secretKey,?128);?? ?? ??????InitRC4Encryption(secretKey,?? ????????????????(uint8_t?*)?&?serversig[dhposServer],?? ????????????????(uint8_t?*)?&?clientsig[dhposClient],?? ????????????????&keyIn,?&keyOut);?? ????}?? ?? ?? ??????reply?=?client2;?? #ifdef?_DEBUG?? ??????memset(reply,?0xff,?RTMP_SIG_SIZE);?? #else?? ??????ip?=?(int32_t?*)reply;?? ??????for?(i?=?0;?i?<?RTMP_SIG_SIZE/4;?i++)?? ????????*ip++?=?rand();?? #endif?? ???????? ??????signatureResp?=?reply+RTMP_SIG_SIZE-SHA256_DIGEST_LENGTH;?? ?? ??????HMACsha256(&serversig[digestPosServer],?SHA256_DIGEST_LENGTH,?? ?????????GenuineFPKey,?sizeof(GenuineFPKey),?digestResp);?? ??????HMACsha256(reply,?RTMP_SIG_SIZE?-?SHA256_DIGEST_LENGTH,?digestResp,?? ?????????SHA256_DIGEST_LENGTH,?signatureResp);?? ?? ???????? ??????RTMP_Log(RTMP_LOGDEBUG,?? ??????"%s:?Calculated?digest?key?from?secure?key?and?server?digest:?",?? ??????__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?digestResp,?SHA256_DIGEST_LENGTH);?? ?? #ifdef?FP10?? ??????if?(type?==?8?)?? ????????{?? ??????uint8_t?*dptr?=?digestResp;?? ??????uint8_t?*sig?=?signatureResp;?? ???????? ??????????for?(i=0;?i<SHA256_DIGEST_LENGTH;?i+=8)?? ????????rtmpe8_sig(sig+i,?sig+i,?dptr[i]?%?15);?? ????????}?? #if?0?? ??????else?if?(type?==?9))?? ????????{?? ??????uint8_t?*dptr?=?digestResp;?? ??????uint8_t?*sig?=?signatureResp;?? ???????? ??????????for?(i=0;?i<SHA256_DIGEST_LENGTH;?i+=8)?? ????????????rtmpe9_sig(sig+i,?sig+i,?dptr[i]?%?15);?? ????????}?? #endif?? #endif?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Client?signature?calculated:",?__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?signatureResp,?SHA256_DIGEST_LENGTH);?? ????}?? ??else?? ????{?? ?????? ??????reply?=?serversig;?? #if?0?? ??????uptime?=?htonl(RTMP_GetTime());?? ??????memcpy(reply+4,?&uptime,?4);?? #endif?? ????}?? ?? #ifdef?_DEBUG?? ??RTMP_Log(RTMP_LOGDEBUG,?"%s:?Sending?handshake?response:?",?? ????__FUNCTION__);?? ??RTMP_LogHex(RTMP_LOGDEBUG,?reply,?RTMP_SIG_SIZE);?? #endif?? ???? ???? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。發(fā)送握手?jǐn)?shù)據(jù)C2");?? ???? ??if?(!WriteN(r,?(char?*)reply,?RTMP_SIG_SIZE))?? ????return?FALSE;?? ?? ???? ???? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。讀取握手?jǐn)?shù)據(jù)S2");?? ???? ??if?(ReadN(r,?(char?*)serversig,?RTMP_SIG_SIZE)?!=?RTMP_SIG_SIZE)?? ????return?FALSE;?? ?? #ifdef?_DEBUG?? ??RTMP_Log(RTMP_LOGDEBUG,?"%s:?2nd?handshake:?",?__FUNCTION__);?? ??RTMP_LogHex(RTMP_LOGDEBUG,?serversig,?RTMP_SIG_SIZE);?? #endif?? ?? ??if?(FP9HandShake)?? ????{?? ??????uint8_t?signature[SHA256_DIGEST_LENGTH];?? ??????uint8_t?digest[SHA256_DIGEST_LENGTH];?? ?? ??????if?(serversig[4]?==?0?&&?serversig[5]?==?0?&&?serversig[6]?==?0?? ??????&&?serversig[7]?==?0)?? ????{?? ??????RTMP_Log(RTMP_LOGDEBUG,?? ??????????"%s:?Wait,?did?the?server?just?refuse?signed?authentication?",?? ??????????__FUNCTION__);?? ????}?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Server?sent?signature:",?__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?&serversig[RTMP_SIG_SIZE?-?SHA256_DIGEST_LENGTH],?? ?????????SHA256_DIGEST_LENGTH);?? ?? ???????? ??????HMACsha256(&clientsig[digestPosClient],?SHA256_DIGEST_LENGTH,?? ?????????GenuineFMSKey,?sizeof(GenuineFMSKey),?digest);?? ??????HMACsha256(serversig,?RTMP_SIG_SIZE?-?SHA256_DIGEST_LENGTH,?digest,?? ?????????SHA256_DIGEST_LENGTH,?signature);?? ?? ???????? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Digest?key:?",?__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?digest,?SHA256_DIGEST_LENGTH);?? ?? #ifdef?FP10?? ??????if?(type?==?8?)?? ????????{?? ??????uint8_t?*dptr?=?digest;?? ??????uint8_t?*sig?=?signature;?? ???????? ??????????for?(i=0;?i<SHA256_DIGEST_LENGTH;?i+=8)?? ????????rtmpe8_sig(sig+i,?sig+i,?dptr[i]?%?15);?? ????????}?? #if?0?? ??????else?if?(type?==?9)?? ????????{?? ??????uint8_t?*dptr?=?digest;?? ??????uint8_t?*sig?=?signature;?? ???????? ??????????for?(i=0;?i<SHA256_DIGEST_LENGTH;?i+=8)?? ????????????rtmpe9_sig(sig+i,?sig+i,?dptr[i]?%?15);?? ????????}?? #endif?? #endif?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Signature?calculated:",?__FUNCTION__);?? ??????RTMP_LogHex(RTMP_LOGDEBUG,?signature,?SHA256_DIGEST_LENGTH);?? ??????if?(memcmp?? ??????(signature,?&serversig[RTMP_SIG_SIZE?-?SHA256_DIGEST_LENGTH],?? ???????SHA256_DIGEST_LENGTH)?!=?0)?? ????{?? ??????RTMP_Log(RTMP_LOGWARNING,?"%s:?Server?not?genuine?Adobe!",?__FUNCTION__);?? ??????return?FALSE;?? ????}?? ??????else?? ????{?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s:?Genuine?Adobe?Flash?Media?Server",?__FUNCTION__);?? ????}?? ?? ??????if?(encrypted)?? ????{?? ??????char?buff[RTMP_SIG_SIZE];?? ???????? ??????r->Link.rc4keyIn?=?keyIn;?? ??????r->Link.rc4keyOut?=?keyOut;?? ?? ?? ???????? ??????if?(r->Link.rc4keyIn)?? ????????{?? ??????????RC4_encrypt((RC4_KEY?*)r->Link.rc4keyIn,?RTMP_SIG_SIZE,?(uint8_t?*)?buff);?? ????????}?? ?? ??????if?(r->Link.rc4keyOut)?? ????????{?? ??????????RC4_encrypt((RC4_KEY?*)r->Link.rc4keyOut,?RTMP_SIG_SIZE,?(uint8_t?*)?buff);?? ????????}?? ????}?? ????}?? ??else?? ????{?? ?????? ?????? ?????????? ????????r->dlg->AppendCInfo("建立連接:第1次連接。比較握手?jǐn)?shù)據(jù)簽名");?? ?????????? ??????if?(memcmp(serversig,?clientsig,?RTMP_SIG_SIZE)?!=?0)?? ????{?? ?????????? ????????r->dlg->AppendCInfo("建立連接:第1次連接。握手?jǐn)?shù)據(jù)簽名不匹配!");?? ?????????? ??????RTMP_Log(RTMP_LOGWARNING,?"%s:?client?signature?does?not?match!",?? ??????????__FUNCTION__);?? ????}?? ????}?? ???? ??r->dlg->AppendCInfo("建立連接:第1次連接。握手成功");?? ???? ??RTMP_Log(RTMP_LOGDEBUG,?"%s:?Handshaking?finished....",?__FUNCTION__);?? ??return?TRUE;?? }??
rtmpdump源代碼(Linux):http://download.csdn.net/detail/leixiaohua1020/6376561
rtmpdump源代碼(VC 2005 工程):http://download.csdn.net/detail/leixiaohua1020/6563163
總結(jié)
以上是生活随笔為你收集整理的RTMPdump(libRTMP)源代码分析 4: 连接第一步——握手(Hand Shake)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。