From 36666c6712040fa6e259eaaafea25e3093724da0 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 26 Jan 2015 17:23:35 -0800 Subject: [PATCH] obs-outputs: Update to latest librtmp version Should be all the fixes and updates made by R1CH, mostly bug fixes as well as IPv6 support --- plugins/obs-outputs/librtmp/amf.c | 7 +- plugins/obs-outputs/librtmp/rtmp.c | 138 ++++++++++++++++++------- plugins/obs-outputs/librtmp/rtmp.h | 5 +- plugins/obs-outputs/librtmp/rtmp_sys.h | 1 + 4 files changed, 111 insertions(+), 40 deletions(-) diff --git a/plugins/obs-outputs/librtmp/amf.c b/plugins/obs-outputs/librtmp/amf.c index fee35e123..ef44f0cda 100644 --- a/plugins/obs-outputs/librtmp/amf.c +++ b/plugins/obs-outputs/librtmp/amf.c @@ -483,6 +483,7 @@ AMF3ReadString(const char *data, AVal *str) return len + nSize; } + return len; } int @@ -504,7 +505,7 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, /* decode name */ if (bDecodeName) { - AVal name; + AVal name = AV_empty; int nRes = AMF3ReadString(pBuffer, &name); if (name.av_len <= 0) @@ -863,7 +864,7 @@ AMFProp_Dump(AMFObjectProperty *prop) void AMFProp_Reset(AMFObjectProperty *prop) { - if (prop->p_type == AMF_OBJECT) + if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY || prop->p_type == AMF_STRICT_ARRAY) AMF_Reset(&prop->p_vu.p_object); else { @@ -1078,7 +1079,7 @@ AMF3_Decode(AMFObject *obj, const char *pBuffer, int nSize, int bAMFData) for (i = 0; i < cd.cd_num; i++) { - AVal memberName; + AVal memberName = AV_empty; len = AMF3ReadString(pBuffer, &memberName); RTMP_Log(RTMP_LOGDEBUG, "Member: %s", memberName.av_val); AMF3CD_AddProp(&cd, &memberName); diff --git a/plugins/obs-outputs/librtmp/rtmp.c b/plugins/obs-outputs/librtmp/rtmp.c index 7fc6d50f2..02cbc8bd3 100644 --- a/plugins/obs-outputs/librtmp/rtmp.c +++ b/plugins/obs-outputs/librtmp/rtmp.c @@ -1101,7 +1101,7 @@ int RTMP_SetupURL2(RTMP *r, char *url, char *playpath) } static int -add_addr_info(struct sockaddr_in *service, AVal *host, int port) +add_addr_info(struct sockaddr_storage *service, AVal *host, int port) { char *hostname; int ret = TRUE; @@ -1116,20 +1116,53 @@ add_addr_info(struct sockaddr_in *service, AVal *host, int port) hostname = host->av_val; } - service->sin_addr.s_addr = inet_addr(hostname); - if (service->sin_addr.s_addr == INADDR_NONE) + 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) { - struct hostent *host = gethostbyname(hostname); - if (host == NULL || host->h_addr == NULL) - { - 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; +#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) + { + memcpy(service, ptr->ai_addr, ptr->ai_addrlen); + break; + } + } + + 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); @@ -1156,9 +1189,9 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service) //best to be explicit, we need overlapped socket #ifdef _WIN32 - r->m_sb.sb_socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); + r->m_sb.sb_socket = WSASocket(service->sa_family, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); #else - r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + r->m_sb.sb_socket = socket(service->sa_family, SOCK_STREAM, IPPROTO_TCP); #endif if (r->m_sb.sb_socket != -1) @@ -1175,7 +1208,7 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service) } } - if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0) + if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr_storage)) < 0) { int err = GetSockError(); if (err == E_CONNREFUSED) @@ -1302,12 +1335,24 @@ RTMP_Connect1(RTMP *r, RTMPPacket *cp) int RTMP_Connect(RTMP *r, RTMPPacket *cp) { - struct sockaddr_in service; +#ifdef _WIN32 + HOSTENT *h; +#endif + struct sockaddr_storage service; if (!r->Link.hostname.av_len) return FALSE; - memset(&service, 0, sizeof(struct sockaddr_in)); - service.sin_family = AF_INET; +#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)); if (r->Link.socksport) { @@ -1334,11 +1379,16 @@ static int SocksNegotiate(RTMP *r) { unsigned long addr; - struct sockaddr_in service; - memset(&service, 0, sizeof(struct sockaddr_in)); + struct sockaddr_storage service; + memset(&service, 0, sizeof(service)); add_addr_info(&service, &r->Link.hostname, r->Link.port); - addr = htonl(service.sin_addr.s_addr); + + // not doing IPv6 socks + if (service.ss_family == AF_INET6) + return FALSE; + + addr = htonl((*(struct sockaddr_in *)&service).sin_addr.s_addr); { char packet[] = @@ -1651,7 +1701,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, (uint8_t*)packet->m_body, packet->m_nBodySize); + RTMP_LogHex(RTMP_LOGDEBUG, (const uint8_t*)packet->m_body, packet->m_nBodySize); #endif } @@ -2201,9 +2251,6 @@ SendFCUnpublish(RTMP *r) SAVC(publish); SAVC(live); -#if 0 -SAVC(record); -#endif static int SendPublish(RTMP *r) @@ -2826,6 +2873,17 @@ 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) { @@ -2875,8 +2933,9 @@ PublisherAuth(RTMP *r, AVal *description) { char *par, *val = NULL, *orig_ptr; AVal user, salt, opaque, challenge, *aptr = NULL; - opaque.av_len = 0; - challenge.av_len = 0; + + 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; ptr = orig_ptr = strdup(token_in); while (ptr) @@ -3064,6 +3123,9 @@ 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) @@ -3119,7 +3181,7 @@ PublisherAuth(RTMP *r, AVal *description) /* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */ /* Extract appname + appinstance without query parameters */ apptmp = r->Link.app; - ptr = strchr(apptmp.av_val, '?'); + ptr = AValChr(&apptmp, '?'); if (ptr) apptmp.av_len = ptr - apptmp.av_val; @@ -3127,6 +3189,8 @@ 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); @@ -3248,10 +3312,6 @@ 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 @@ -3924,6 +3984,7 @@ 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__, r->m_sb.sb_socket); @@ -4028,7 +4089,10 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet) packet->m_nInfoField2 = DecodeInt32LE(header + 7); } } - if (packet->m_nTimeStamp == 0xffffff) + + extendedTimestamp = (packet->m_nTimeStamp == 0xffffff); + + if (extendedTimestamp) { if (ReadN(r, header + nSize, 4) != 4) { @@ -4083,6 +4147,8 @@ 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)) { @@ -5339,8 +5405,8 @@ stopKeyframeSearch: if (recopy) { - len = (unsigned int)(ret) > buflen ? buflen : (unsigned int)ret; - memcpy(buf, r->m_read.buf, len); + len = ret > (int)(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; } @@ -5386,6 +5452,7 @@ 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) { @@ -5403,6 +5470,7 @@ 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; } diff --git a/plugins/obs-outputs/librtmp/rtmp.h b/plugins/obs-outputs/librtmp/rtmp.h index 3113af5f0..28e449d53 100644 --- a/plugins/obs-outputs/librtmp/rtmp.h +++ b/plugins/obs-outputs/librtmp/rtmp.h @@ -39,7 +39,8 @@ #ifdef _WIN32 #pragma warning(disable:4996) //depricated warnings #pragma warning(disable:4244) //64bit defensive mechanism, fixed the ones that mattered -#include +#include +#include #else #include #include @@ -253,7 +254,7 @@ extern "C" typedef struct RTMP_BINDINFO { - struct sockaddr_in addr; + struct sockaddr_storage addr; int addrLen; } RTMP_BINDINFO; diff --git a/plugins/obs-outputs/librtmp/rtmp_sys.h b/plugins/obs-outputs/librtmp/rtmp_sys.h index 32847220b..6f2b79a96 100644 --- a/plugins/obs-outputs/librtmp/rtmp_sys.h +++ b/plugins/obs-outputs/librtmp/rtmp_sys.h @@ -38,6 +38,7 @@ #include #include +#include #ifdef _MSC_VER /* MSVC */