本篇文章分析一下RTMPdump里面的建立一个网络连接过程中的函数调用。
函数调用过程如下:
RTMP_Connect
->add_addr_info:填充struct sockaddr_in结构体用于之后的socket通信
->RTMP_Connect0:主要用于建立Socket连接,并未开始真正的建立RTMP连接
->RTMP_Connect1:这是真正建立RTMP连接的函数
->HandShake:握手
->SendConnectPacket:真正建立连接的函数
RTMP_Connect:
bool RTMP_Connect(RTMP *r, RTMPPacket *cp)
{
struct sockaddr_in service;
if (!r->Link.hostname.av_len)
return false;
memset(&service, 0, sizeof(struct sockaddr_in));
service.sin_family = AF_INET;
if (r->Link.socksport)
{
/* Connect via SOCKS */
if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
return false;
}
else
{
/* zx 填充struct sockaddr_in结构体用于之后的socket通信 */
if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
return false;
}
/* zx 一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数 */
if (!RTMP_Connect0(r, (struct sockaddr *)&service))
return false;
r->m_bSendCounter = true;
return RTMP_Connect1(r, cp);
}
add_addr_info函数: 填充struct sockaddr_in结构体用于之后的socket通信
static bool
add_addr_info(struct sockaddr_in *service, AVal *host, int port)
{
char *hostname;
bool ret = true;
if (host->av_val[host->av_len])
{
hostname = malloc(host->av_len+1);
memcpy(hostname, host->av_val, host->av_len);
hostname[host->av_len] = '\0';
}
else
{
hostname = host->av_val;
}
/* zx inet_addr函数将一个IP字符串转化为一个网络字节序的整数值 */
service->sin_addr.s_addr = inet_addr(hostname);
if (service->sin_addr.s_addr == INADDR_NONE) /* zx 传入的字符串不是一个合法的Internet地址就返回INADDR_NONE */
{
struct hostent *host = gethostbyname(hostname); /* zx gethostbyname函数将主机名转化为网络字节序的整数ip值 */
if (host == NULL || host->h_addr == NULL)
{
RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
ret = false;
goto finish;
}
service->sin_addr = *(struct in_addr *)host->h_addr;
}
/* zx 端口号的主机字节序转化为网络字节序 */
service->sin_port = htons(port);
finish:
if (hostname != host->av_val)
free(hostname);
return ret;
}
RTMP_Connect0() 主要用于建立Socket连接,并未开始真正的建立RTMP连接:
bool RTMP_Connect0(RTMP *r, struct sockaddr * service)
{
int on = 1;
r->m_sb.sb_timedout = false;
r->m_pausing = 0;
r->m_fDuration = 0.0;
r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (r->m_sb.sb_socket != -1)
{
/* zx 客户端调用connect与服务端创建连接 */
if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
{
int err = GetSockError();
RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)", __FUNCTION__, err, strerror(err));
RTMP_Close(r);
return false;
}
if (r->Link.socksport)
{
RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
if (!SocksNegotiate(r))
{
RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
RTMP_Close(r);
return false;
}
}
}
else
{
RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
GetSockError());
return false;
}
/* set timeout */
{
SET_RCVTIMEO(tv, r->Link.timeout);
/* zx 设置接收超时时间 */
if (setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
{
RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!", __FUNCTION__, r->Link.timeout);
}
}
/* zx 禁止nagle算法 */
setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
return true;
}
RTMP_Connect1(),这是真正建立RTMP连接的函数:
bool RTMP_Connect1(RTMP *r, RTMPPacket *cp)
{
if (r->Link.protocol & RTMP_FEATURE_SSL)
{
#if defined(CRYPTO) && !defined(NO_SSL)
TLS_client(RTMP_TLS_ctx, r->m_sb.sb_ssl);
TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
if (TLS_connect(r->m_sb.sb_ssl) < 0)
{
RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
RTMP_Close(r);
return false;
}
#else
RTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);
RTMP_Close(r);
return false;
#endif
}
if (r->Link.protocol & RTMP_FEATURE_HTTP)
{
r->m_msgCounter = 1;
r->m_clientID.av_val = NULL;
r->m_clientID.av_len = 0;
HTTP_Post(r, RTMPT_OPEN, "", 1);
HTTP_read(r, 1);
r->m_msgCounter = 0;
}
RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
if (!HandShake(r, true)) /* zx 握手 */
{
RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);
RTMP_Close(r);
return false;
}
RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);
if (!SendConnectPacket(r, cp)) /* zx 真正建立网络连接 */
{
RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
RTMP_Close(r);
return false;
}
return true;
}