|
|
|
@@ -642,7 +642,7 @@ int RTMP_AddStream(RTMP *r, const char *playpath)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
add_addr_info(struct sockaddr_storage *service, AVal *host, int port)
|
|
|
|
|
add_addr_info(struct sockaddr_in *service, AVal *host, int port)
|
|
|
|
|
{
|
|
|
|
|
char *hostname;
|
|
|
|
|
int ret = TRUE;
|
|
|
|
@@ -657,53 +657,20 @@ add_addr_info(struct sockaddr_storage *service, AVal *host, int port)
|
|
|
|
|
hostname = host->av_val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct addrinfo hints;
|
|
|
|
|
struct addrinfo *result = NULL;
|
|
|
|
|
struct addrinfo *ptr = NULL;
|
|
|
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
|
|
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
|
|
|
|
|
|
service->ss_family = AF_UNSPEC;
|
|
|
|
|
|
|
|
|
|
char portStr[8];
|
|
|
|
|
|
|
|
|
|
sprintf(portStr, "%d", port);
|
|
|
|
|
|
|
|
|
|
int err = getaddrinfo(hostname, portStr, &hints, &result);
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
service->sin_addr.s_addr = inet_addr(hostname);
|
|
|
|
|
if (service->sin_addr.s_addr == INADDR_NONE)
|
|
|
|
|
{
|
|
|
|
|
#ifndef _WIN32
|
|
|
|
|
#define gai_strerrorA gai_strerror
|
|
|
|
|
#endif
|
|
|
|
|
RTMP_Log(RTMP_LOGERROR, "Could not resolve %s: %s (%d)", hostname, gai_strerrorA(GetSockError()), GetSockError());
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
goto finish;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// they should come back in OS preferred order
|
|
|
|
|
for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
|
|
|
|
|
{
|
|
|
|
|
if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
|
|
|
|
|
struct hostent *host = gethostbyname(hostname);
|
|
|
|
|
if (host == NULL || host->h_addr == NULL)
|
|
|
|
|
{
|
|
|
|
|
memcpy(service, ptr->ai_addr, ptr->ai_addrlen);
|
|
|
|
|
break;
|
|
|
|
|
RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s, error: %d)", hostname, GetSockError());
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
goto finish;
|
|
|
|
|
}
|
|
|
|
|
service->sin_addr = *(struct in_addr *)host->h_addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
freeaddrinfo(result);
|
|
|
|
|
|
|
|
|
|
if (service->ss_family == AF_UNSPEC)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Log(RTMP_LOGERROR, "Could not resolve server '%s': no valid address found", hostname);
|
|
|
|
|
ret = FALSE;
|
|
|
|
|
goto finish;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
service->sin_port = htons(port);
|
|
|
|
|
finish:
|
|
|
|
|
if (hostname != host->av_val)
|
|
|
|
|
free(hostname);
|
|
|
|
@@ -730,9 +697,9 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service)
|
|
|
|
|
|
|
|
|
|
//best to be explicit, we need overlapped socket
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
r->m_sb.sb_socket = WSASocket(service->sa_family, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
|
|
|
|
|
r->m_sb.sb_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
|
|
|
|
|
#else
|
|
|
|
|
r->m_sb.sb_socket = socket(service->sa_family, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
|
r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (r->m_sb.sb_socket != INVALID_SOCKET)
|
|
|
|
@@ -749,7 +716,7 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr_storage)) < 0)
|
|
|
|
|
if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
|
|
|
|
|
{
|
|
|
|
|
int err = GetSockError();
|
|
|
|
|
if (err == E_CONNREFUSED)
|
|
|
|
@@ -876,24 +843,12 @@ RTMP_Connect1(RTMP *r, RTMPPacket *cp)
|
|
|
|
|
int
|
|
|
|
|
RTMP_Connect(RTMP *r, RTMPPacket *cp)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
HOSTENT *h;
|
|
|
|
|
#endif
|
|
|
|
|
struct sockaddr_storage service;
|
|
|
|
|
struct sockaddr_in service;
|
|
|
|
|
if (!r->Link.hostname.av_len)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
//COMODO security software sandbox blocks all DNS by returning "host not found"
|
|
|
|
|
h = gethostbyname("localhost");
|
|
|
|
|
if (!h && GetLastError() == WSAHOST_NOT_FOUND)
|
|
|
|
|
{
|
|
|
|
|
RTMP_Log(RTMP_LOGERROR, "RTMP_Connect: Connection test failed. This error is likely caused by Comodo Internet Security running OBS in sandbox mode. Please add OBS to the Comodo automatic sandbox exclusion list, restart OBS and try again (11001).");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
memset(&service, 0, sizeof(service));
|
|
|
|
|
memset(&service, 0, sizeof(struct sockaddr_in));
|
|
|
|
|
service.sin_family = AF_INET;
|
|
|
|
|
|
|
|
|
|
if (r->Link.socksport)
|
|
|
|
|
{
|
|
|
|
@@ -920,16 +875,11 @@ static int
|
|
|
|
|
SocksNegotiate(RTMP *r)
|
|
|
|
|
{
|
|
|
|
|
unsigned long addr;
|
|
|
|
|
struct sockaddr_storage service;
|
|
|
|
|
memset(&service, 0, sizeof(service));
|
|
|
|
|
struct sockaddr_in service;
|
|
|
|
|
memset(&service, 0, sizeof(struct sockaddr_in));
|
|
|
|
|
|
|
|
|
|
add_addr_info(&service, &r->Link.hostname, r->Link.port);
|
|
|
|
|
|
|
|
|
|
// not doing IPv6 socks
|
|
|
|
|
if (service.ss_family == AF_INET6)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
addr = htonl((*(struct sockaddr_in *)&service).sin_addr.s_addr);
|
|
|
|
|
addr = htonl(service.sin_addr.s_addr);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
char packet[] =
|
|
|
|
@@ -1242,7 +1192,7 @@ RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
|
|
|
|
|
RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
|
|
|
|
|
packet->m_packetType);
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
|
RTMP_LogHex(RTMP_LOGDEBUG, (const uint8_t*)packet->m_body, packet->m_nBodySize);
|
|
|
|
|
RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t*)packet->m_body, packet->m_nBodySize);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1792,6 +1742,9 @@ SendFCUnpublish(RTMP *r, int streamIdx)
|
|
|
|
|
|
|
|
|
|
SAVC(publish);
|
|
|
|
|
SAVC(live);
|
|
|
|
|
#if 0
|
|
|
|
|
SAVC(record);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
SendPublish(RTMP *r, int streamIdx)
|
|
|
|
@@ -2414,17 +2367,6 @@ static void hexenc(unsigned char *inbuf, int len, char *dst)
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *AValChr(AVal *av, char c)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < av->av_len; i++)
|
|
|
|
|
{
|
|
|
|
|
if (av->av_val[i] == c)
|
|
|
|
|
return &av->av_val[i];
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
PublisherAuth(RTMP *r, AVal *description)
|
|
|
|
|
{
|
|
|
|
@@ -2474,9 +2416,8 @@ PublisherAuth(RTMP *r, AVal *description)
|
|
|
|
|
{
|
|
|
|
|
char *par, *val = NULL, *orig_ptr;
|
|
|
|
|
AVal user, salt, opaque, challenge, *aptr = NULL;
|
|
|
|
|
|
|
|
|
|
opaque.av_len = challenge.av_len = salt.av_len = user.av_len = 0;
|
|
|
|
|
opaque.av_val = challenge.av_val = salt.av_val = user.av_val = NULL;
|
|
|
|
|
opaque.av_len = 0;
|
|
|
|
|
challenge.av_len = 0;
|
|
|
|
|
|
|
|
|
|
ptr = orig_ptr = strdup(token_in);
|
|
|
|
|
while (ptr)
|
|
|
|
@@ -2664,9 +2605,6 @@ PublisherAuth(RTMP *r, AVal *description)
|
|
|
|
|
/* cnonce = hexenc(4 random bytes) (initialized on first connection) */
|
|
|
|
|
char cnonce[9];
|
|
|
|
|
|
|
|
|
|
nonce.av_len = user.av_len = 0;
|
|
|
|
|
nonce.av_val = user.av_val = NULL;
|
|
|
|
|
|
|
|
|
|
ptr = orig_ptr = strdup(token_in);
|
|
|
|
|
/* Extract parameters (we need user and nonce) */
|
|
|
|
|
while (ptr)
|
|
|
|
@@ -2722,7 +2660,7 @@ PublisherAuth(RTMP *r, AVal *description)
|
|
|
|
|
/* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */
|
|
|
|
|
/* Extract appname + appinstance without query parameters */
|
|
|
|
|
apptmp = r->Link.app;
|
|
|
|
|
ptr = AValChr(&apptmp, '?');
|
|
|
|
|
ptr = strchr(apptmp.av_val, '?');
|
|
|
|
|
if (ptr)
|
|
|
|
|
apptmp.av_len = ptr - apptmp.av_val;
|
|
|
|
|
|
|
|
|
@@ -2730,8 +2668,6 @@ PublisherAuth(RTMP *r, AVal *description)
|
|
|
|
|
MD5_Update(&md5ctx, (void *)method, sizeof(method)-1);
|
|
|
|
|
MD5_Update(&md5ctx, ":/", 2);
|
|
|
|
|
MD5_Update(&md5ctx, apptmp.av_val, apptmp.av_len);
|
|
|
|
|
if (!AValChr(&apptmp, '/'))
|
|
|
|
|
MD5_Update(&md5ctx, "/_definst_", sizeof("/_definst_") - 1);
|
|
|
|
|
MD5_Final(md5sum_val, &md5ctx);
|
|
|
|
|
RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:/%.*s) =>", __FUNCTION__,
|
|
|
|
|
method, apptmp.av_len, apptmp.av_val);
|
|
|
|
@@ -2853,6 +2789,10 @@ static const AVal av_NetStream_Play_UnpublishNotify =
|
|
|
|
|
static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
|
|
|
|
|
static const AVal av_NetStream_Publish_Rejected = AVC("NetStream.Publish.Rejected");
|
|
|
|
|
static const AVal av_NetStream_Publish_Denied = AVC("NetStream.Publish.Denied");
|
|
|
|
|
#if 0
|
|
|
|
|
static const AVal av_NetConnection_Connect_Rejected =
|
|
|
|
|
AVC("NetConnection.Connect.Rejected");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
|
|
|
|
|
static int
|
|
|
|
@@ -3534,7 +3474,6 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
|
|
|
|
|
char *header = (char *)hbuf;
|
|
|
|
|
int nSize, hSize, nToRead, nChunk;
|
|
|
|
|
// int didAlloc = FALSE;
|
|
|
|
|
int extendedTimestamp = 0;
|
|
|
|
|
|
|
|
|
|
RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, (int)r->m_sb.sb_socket);
|
|
|
|
|
|
|
|
|
@@ -3639,10 +3578,7 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
|
|
|
|
|
packet->m_nInfoField2 = DecodeInt32LE(header + 7);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extendedTimestamp = (packet->m_nTimeStamp == 0xffffff);
|
|
|
|
|
|
|
|
|
|
if (extendedTimestamp)
|
|
|
|
|
if (packet->m_nTimeStamp == 0xffffff)
|
|
|
|
|
{
|
|
|
|
|
if (ReadN(r, header + nSize, 4) != 4)
|
|
|
|
|
{
|
|
|
|
@@ -3697,8 +3633,6 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
|
|
|
|
|
if (!r->m_vecChannelsIn[packet->m_nChannel])
|
|
|
|
|
r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
|
|
|
|
|
memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
|
|
|
|
|
if (extendedTimestamp)
|
|
|
|
|
r->m_vecChannelsIn[packet->m_nChannel]->m_nTimeStamp = 0xffffff;
|
|
|
|
|
|
|
|
|
|
if (RTMPPacket_IsReady(packet))
|
|
|
|
|
{
|
|
|
|
@@ -4967,8 +4901,8 @@ stopKeyframeSearch:
|
|
|
|
|
|
|
|
|
|
if (recopy)
|
|
|
|
|
{
|
|
|
|
|
len = ret > (int)(buflen) ? buflen : (unsigned int)(ret);
|
|
|
|
|
memcpy(buf, r->m_read.buf, len);
|
|
|
|
|
len = (unsigned int)(ret) > buflen ? buflen : (unsigned int)ret;
|
|
|
|
|
memcpy(buf, r->m_read.buf, len);
|
|
|
|
|
r->m_read.bufpos = r->m_read.buf + len;
|
|
|
|
|
r->m_read.buflen = ret - len;
|
|
|
|
|
}
|
|
|
|
@@ -5014,7 +4948,6 @@ fail:
|
|
|
|
|
memcpy(mybuf, flvHeader, sizeof(flvHeader));
|
|
|
|
|
r->m_read.buf += sizeof(flvHeader);
|
|
|
|
|
r->m_read.buflen -= sizeof(flvHeader);
|
|
|
|
|
cnt += sizeof(flvHeader);
|
|
|
|
|
|
|
|
|
|
while (r->m_read.timestamp == 0)
|
|
|
|
|
{
|
|
|
|
@@ -5032,7 +4965,6 @@ fail:
|
|
|
|
|
{
|
|
|
|
|
mybuf = realloc(mybuf, cnt + nRead);
|
|
|
|
|
memcpy(mybuf+cnt, r->m_read.buf, nRead);
|
|
|
|
|
free(r->m_read.buf);
|
|
|
|
|
r->m_read.buf = mybuf+cnt+nRead;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|