diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2015-01-30 15:25:44 +0100 |
---|---|---|
committer | Rainer Hochecker <fernetmenta@online.de> | 2015-01-30 15:25:44 +0100 |
commit | 2be805c56776716d2fc269b5376ebf3f495e7a98 (patch) | |
tree | 2845df6368c1db8e0f4c376b31f18795f28ec984 /tools | |
parent | 5ff422b4aa2cb8fbc9ca8df72a1f3c70786f2eb2 (diff) | |
parent | 679d444a4e044d63ea337455c295fbd38c2b1b86 (diff) |
Merge pull request #6283 from FernetMenta/rtmp
bump librtmp
Diffstat (limited to 'tools')
-rw-r--r-- | tools/depends/target/librtmp/Makefile | 7 | ||||
-rw-r--r-- | tools/depends/target/librtmp/librtmp-60-second-fix.patch | 1913 | ||||
-rw-r--r-- | tools/depends/target/librtmp/prefix.patch | 2 |
3 files changed, 4 insertions, 1918 deletions
diff --git a/tools/depends/target/librtmp/Makefile b/tools/depends/target/librtmp/Makefile index 271873e043..15829b4648 100644 --- a/tools/depends/target/librtmp/Makefile +++ b/tools/depends/target/librtmp/Makefile @@ -3,7 +3,7 @@ DEPS= ../../Makefile.include Makefile prefix.patch # lib name, version LIBNAME=rtmpdump -VERSION=e0056c51cc1710c9a44d2a2c4e2f344fa9cabcf4 +VERSION=a107cef9b392616dff54fabfd37f985ee2190a6f SOURCE=$(LIBNAME)-$(VERSION) ARCHIVE=$(SOURCE).tar.gz # configuration settings @@ -27,7 +27,6 @@ $(PLATFORM): $(TARBALLS_LOCATION)/$(ARCHIVE) $(DEPS) rm -rf $(PLATFORM)/*; mkdir -p $(PLATFORM) cd $(PLATFORM); $(ARCHIVE_TOOL) $(ARCHIVE_TOOL_FLAGS) $(TARBALLS_LOCATION)/$(ARCHIVE) cd $(PLATFORM); patch -p0 < ../prefix.patch - cd $(PLATFORM); patch -p1 < ../librtmp-60-second-fix.patch cd $(PLATFORM)/librtmp; patch -p0 < ../../libm.patch sed -i -e 's|CC=|#CC=|' $(PLATFORM)/librtmp/Makefile sed -i -e 's|LD=|#LD=|' $(PLATFORM)/librtmp/Makefile @@ -40,8 +39,8 @@ $(LIBDYLIB): $(PLATFORM) $(MAKE) SYS=$(SYS) prefix=$(PREFIX) -C $(PLATFORM)/librtmp install ifeq ($(OS),android) rm -f $(PREFIX)/lib/librtmp.la $(PREFIX)/lib/librtmp.so - mv -f $(PREFIX)/lib/librtmp.so.0 $(PREFIX)/lib/librtmp.so - $(RPL) -e "librtmp.so.0" "librtmp.so\x00\x00" $(PREFIX)/lib/librtmp.so + mv -f $(PREFIX)/lib/librtmp.so.1 $(PREFIX)/lib/librtmp.so + $(RPL) -e "librtmp.so.1" "librtmp.so\x00\x00" $(PREFIX)/lib/librtmp.so -$(READELF) --dynamic $(PREFIX)/lib/librtmp.so | grep ibrary endif touch $@ diff --git a/tools/depends/target/librtmp/librtmp-60-second-fix.patch b/tools/depends/target/librtmp/librtmp-60-second-fix.patch deleted file mode 100644 index 2914fc1b8e..0000000000 --- a/tools/depends/target/librtmp/librtmp-60-second-fix.patch +++ /dev/null @@ -1,1913 +0,0 @@ -diff --git a/librtmp/amf.c b/librtmp/amf.c -index ce84f81..a25bc04 100644 ---- a/librtmp/amf.c -+++ b/librtmp/amf.c -@@ -610,6 +610,9 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize, - return -1; - } - -+ if (*pBuffer == AMF_NULL) -+ bDecodeName = 0; -+ - if (bDecodeName && nSize < 4) - { /* at least name (length + at least 1 byte) and 1 byte of data */ - RTMP_Log(RTMP_LOGDEBUG, -@@ -801,8 +804,8 @@ AMFProp_Dump(AMFObjectProperty *prop) - } - else - { -- name.av_val = "no-name."; -- name.av_len = sizeof("no-name.") - 1; -+ name.av_val = "no-name"; -+ name.av_len = sizeof("no-name") - 1; - } - if (name.av_len > 18) - name.av_len = 18; -diff --git a/librtmp/dh.h b/librtmp/dh.h -index 9959532..e29587b 100644 ---- a/librtmp/dh.h -+++ b/librtmp/dh.h -@@ -61,7 +61,7 @@ static int MDH_generate_key(MDH *dh) - MP_set(&dh->ctx.P, dh->p); - MP_set(&dh->ctx.G, dh->g); - dh->ctx.len = 128; -- dhm_make_public(&dh->ctx, 1024, out, 1, havege_rand, &RTMP_TLS_ctx->hs); -+ dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs); - MP_new(dh->pub_key); - MP_new(dh->priv_key); - MP_set(dh->pub_key, &dh->ctx.GX); -diff --git a/librtmp/handshake.h b/librtmp/handshake.h -index 0438486..102ba82 100644 ---- a/librtmp/handshake.h -+++ b/librtmp/handshake.h -@@ -965,8 +965,18 @@ HandShake(RTMP * r, int FP9HandShake) - __FUNCTION__); - RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE); - #endif -- if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE)) -- return FALSE; -+ if (r->Link.CombineConnectPacket) -+ { -+ char *HandshakeResponse = malloc(RTMP_SIG_SIZE); -+ memcpy(HandshakeResponse, (char *) reply, RTMP_SIG_SIZE); -+ r->Link.HandshakeResponse.av_val = HandshakeResponse; -+ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE; -+ } -+ else -+ { -+ if (!WriteN(r, (char *) reply, RTMP_SIG_SIZE)) -+ return FALSE; -+ } - - /* 2nd part of handshake */ - if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) -diff --git a/librtmp/hashswf.c b/librtmp/hashswf.c -index 9f4e2c0..eeed34c 100644 ---- a/librtmp/hashswf.c -+++ b/librtmp/hashswf.c -@@ -70,7 +70,7 @@ extern TLS_CTX RTMP_TLS_ctx; - - #endif /* CRYPTO */ - --#define AGENT "Mozilla/5.0" -+#define AGENT "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0" - - HTTPResult - HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) -@@ -528,7 +528,7 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, - - if (strncmp(buf, "url: ", 5)) - continue; -- if (strncmp(buf + 5, url, hlen)) -+ if (strncmp(buf + 5, url, strlen(buf + 5) - 1)) - continue; - r1 = strrchr(buf, '/'); - i = strlen(r1); -diff --git a/librtmp/log.c b/librtmp/log.c -index 0012985..856e3e4 100644 ---- a/librtmp/log.c -+++ b/librtmp/log.c -@@ -52,8 +52,8 @@ static void rtmp_log_default(int level, const char *format, va_list vl) - vsnprintf(str, MAX_PRINT_LEN-1, format, vl); - - /* Filter out 'no-name' */ -- if ( RTMP_debuglevel<RTMP_LOGALL && strstr(str, "no-name" ) != NULL ) -- return; -+ if (RTMP_debuglevel < RTMP_LOGDEBUG && strstr(str, "no-name") != NULL) -+ return; - - if ( !fmsg ) fmsg = stderr; - -diff --git a/librtmp/rtmp.c b/librtmp/rtmp.c -index 52d0254..bef37aa 100644 ---- a/librtmp/rtmp.c -+++ b/librtmp/rtmp.c -@@ -27,6 +27,7 @@ - #include <stdlib.h> - #include <string.h> - #include <assert.h> -+#include <math.h> - - #include "rtmp_sys.h" - #include "log.h" -@@ -45,6 +46,7 @@ TLS_CTX RTMP_TLS_ctx; - - #define RTMP_SIG_SIZE 1536 - #define RTMP_LARGE_HEADER_SIZE 12 -+#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) - - static const int packetSize[] = { 12, 8, 4, 1 }; - -@@ -97,6 +99,9 @@ static int SendFCSubscribe(RTMP *r, AVal *subscribepath); - static int SendPlay(RTMP *r); - static int SendBytesReceived(RTMP *r); - static int SendUsherToken(RTMP *r, AVal *usherToken); -+static int SendInvoke(RTMP *r, AVal *Command, int queue); -+static int SendGetStreamLength(RTMP *r); -+static int strsplit(char *src, int srclen, char delim, char ***params); - - #if 0 /* unused */ - static int SendBGHasStream(RTMP *r, double dId, AVal *playpath); -@@ -259,6 +264,8 @@ RTMP_Init(RTMP *r) - r->m_fVideoCodecs = 252.0; - r->Link.timeout = 30; - r->Link.swfAge = 30; -+ r->Link.CombineConnectPacket = TRUE; -+ r->Link.ConnectPacket = FALSE; - } - - void -@@ -337,6 +344,7 @@ RTMP_SetupStream(RTMP *r, - AVal *flashVer, - AVal *subscribepath, - AVal *usherToken, -+ AVal *WeebToken, - int dStart, - int dStop, int bLiveStream, long int timeout) - { -@@ -359,6 +367,8 @@ RTMP_SetupStream(RTMP *r, - RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val); - if (usherToken && usherToken->av_val) - RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val); -+ if (WeebToken && WeebToken->av_val) -+ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", WeebToken->av_val); - if (flashVer && flashVer->av_val) - RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val); - if (dStart > 0) -@@ -426,6 +436,8 @@ RTMP_SetupStream(RTMP *r, - r->Link.subscribepath = *subscribepath; - if (usherToken && usherToken->av_len) - r->Link.usherToken = *usherToken; -+ if (WeebToken && WeebToken->av_len) -+ r->Link.WeebToken = *WeebToken; - r->Link.seekTime = dStart; - r->Link.stopTime = dStop; - if (bLiveStream) -@@ -483,14 +495,22 @@ static struct urlopt { - "Stream is live, no seeking possible" }, - { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0, - "Stream to subscribe to" }, -- { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0, -- "Justin.tv authentication token" }, -- { AVC("token"), OFF(Link.token), OPT_STR, 0, -+ { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0, -+ "Justin.tv authentication token"}, -+ { AVC("weeb"), OFF(Link.WeebToken), OPT_STR, 0, -+ "Weeb.tv authentication token"}, -+ { AVC("token"), OFF(Link.token), OPT_STR, 0, - "Key for SecureToken response" }, - { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV, - "Perform SWF Verification" }, - { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0, - "Number of days to use cached SWF hash" }, -+#ifdef CRYPTO -+ { AVC("swfsize"), OFF(Link.swfSize), OPT_INT, 0, -+ "Size of the decompressed SWF file"}, -+ { AVC("swfhash"), OFF(Link.swfHash), OPT_STR, 0, -+ "SHA256 hash of the decompressed SWF file"}, -+#endif - { AVC("start"), OFF(Link.seekTime), OPT_INT, 0, - "Stream start position in milliseconds" }, - { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0, -@@ -751,9 +771,16 @@ int RTMP_SetupURL(RTMP *r, char *url) - } - - #ifdef CRYPTO -- if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len) -- RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, -- (unsigned char *)r->Link.SWFHash, r->Link.swfAge); -+ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %d %d %s\n", r->Link.swfSize, r->Link.swfHash.av_len, r->Link.swfHash.av_val); -+ if (r->Link.swfSize && r->Link.swfHash.av_len) -+ { -+ int i, j = 0; -+ for (i = 0; i < r->Link.swfHash.av_len; i += 2) -+ r->Link.SWFHash[j++] = (HEX2BIN(r->Link.swfHash.av_val[i]) << 4) | HEX2BIN(r->Link.swfHash.av_val[i + 1]); -+ r->Link.SWFSize = (uint32_t) r->Link.swfSize; -+ } -+ else if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len) -+ RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, (unsigned char *) r->Link.SWFHash, r->Link.swfAge); - #endif - - if (r->Link.port == 0) -@@ -854,6 +881,8 @@ RTMP_Connect0(RTMP *r, struct sockaddr * service) - } - - setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)); -+ if (r->Link.protocol & RTMP_FEATURE_HTTP) -+ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof (on)); - - return TRUE; - } -@@ -1308,8 +1337,24 @@ ReadN(RTMP *r, char *buffer, int n) - return 0; - } - } -- if (r->m_resplen && !r->m_sb.sb_size) -- RTMPSockBuf_Fill(&r->m_sb); -+ -+ // Try to fill the whole buffer. previous buffer needs to be consumed -+ // completely before receiving new data. -+ if (r->m_resplen && (r->m_sb.sb_size <= 0)) -+ { -+ do -+ { -+ nBytes = RTMPSockBuf_Fill(&r->m_sb); -+ if (nBytes == -1) -+ { -+ if (!r->m_sb.sb_timedout) -+ RTMP_Close(r); -+ return 0; -+ } -+ } -+ while (r->m_resplen && (r->m_sb.sb_size < r->m_resplen) && (nBytes > 0)); -+ } -+ - avail = r->m_sb.sb_size; - if (avail > r->m_resplen) - avail = r->m_resplen; -@@ -1336,10 +1381,9 @@ ReadN(RTMP *r, char *buffer, int n) - r->m_sb.sb_size -= nRead; - nBytes = nRead; - r->m_nBytesIn += nRead; -- if (r->m_bSendCounter -- && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10)) -- if (!SendBytesReceived(r)) -- return FALSE; -+ if (r->m_bSendCounter && r->m_nBytesIn > (r->m_nBytesInSent + r->m_nClientBW / 10)) -+ if (!SendBytesReceived(r)) -+ return FALSE; - } - /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */ - #ifdef _DEBUG -@@ -1390,6 +1434,16 @@ WriteN(RTMP *r, const char *buffer, int n) - } - #endif - -+ if (r->Link.ConnectPacket) -+ { -+ char *ConnectPacket = malloc(r->Link.HandshakeResponse.av_len + n); -+ memcpy(ConnectPacket, r->Link.HandshakeResponse.av_val, r->Link.HandshakeResponse.av_len); -+ memcpy(ConnectPacket + r->Link.HandshakeResponse.av_len, ptr, n); -+ ptr = ConnectPacket; -+ n += r->Link.HandshakeResponse.av_len; -+ r->Link.ConnectPacket = FALSE; -+ } -+ - while (n > 0) - { - int nBytes; -@@ -1455,6 +1509,9 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) - char pbuf[4096], *pend = pbuf + sizeof(pbuf); - char *enc; - -+ if (r->Link.CombineConnectPacket) -+ r->Link.ConnectPacket = TRUE; -+ - if (cp) - return RTMP_SendPacket(r, cp, TRUE); - -@@ -1667,7 +1724,7 @@ SendUsherToken(RTMP *r, AVal *usherToken) - packet.m_hasAbsTimestamp = 0; - packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; - -- RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val); -+ RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %.*s", usherToken->av_len, usherToken->av_val); - enc = packet.m_body; - enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken); - enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -@@ -2096,10 +2153,8 @@ SendPlay(RTMP *r) - enc = AMF_EncodeNumber(enc, pend, -1000.0); - else - { -- if (r->Link.seekTime > 0.0) -- enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */ -- else -- enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */ -+ if (r->Link.seekTime > 0.0 || r->Link.stopTime) -+ enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */ - } - if (!enc) - return FALSE; -@@ -2215,7 +2270,7 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) - int nSize; - char *buf; - -- RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType); -+ RTMP_Log(RTMP_LOGDEBUG, "sending ctrl, type: 0x%04x", (unsigned short)nType); - - packet.m_nChannel = 0x02; /* control channel (ping) */ - packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -@@ -2247,8 +2302,8 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) - } - else if (nType == 0x1A) - { -- *buf = nObject & 0xff; -- } -+ *buf = nObject & 0xff; -+ } - else - { - if (nSize > 2) -@@ -2305,6 +2360,7 @@ AV_clear(RTMP_METHOD *vals, int num) - free(vals); - } - -+SAVC(onBWCheck); - SAVC(onBWDone); - SAVC(onFCSubscribe); - SAVC(onFCUnsubscribe); -@@ -2314,24 +2370,26 @@ SAVC(_error); - SAVC(close); - SAVC(code); - SAVC(level); -+SAVC(description); - SAVC(onStatus); - SAVC(playlist_ready); - static const AVal av_NetStream_Failed = AVC("NetStream.Failed"); - static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed"); --static const AVal av_NetStream_Play_StreamNotFound = --AVC("NetStream.Play.StreamNotFound"); --static const AVal av_NetConnection_Connect_InvalidApp = --AVC("NetConnection.Connect.InvalidApp"); -+static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound"); -+static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp"); - static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start"); - static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete"); - static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); - static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify"); - static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify"); --static const AVal av_NetStream_Play_PublishNotify = --AVC("NetStream.Play.PublishNotify"); --static const AVal av_NetStream_Play_UnpublishNotify = --AVC("NetStream.Play.UnpublishNotify"); -+static const AVal av_NetStream_Play_PublishNotify = AVC("NetStream.Play.PublishNotify"); -+static const AVal av_NetStream_Play_UnpublishNotify = AVC("NetStream.Play.UnpublishNotify"); - static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start"); -+static const AVal av_NetConnection_confStream = AVC("NetConnection.confStream"); -+static const AVal av_verifyClient = AVC("verifyClient"); -+static const AVal av_sendStatus = AVC("sendStatus"); -+static const AVal av_getStreamLength = AVC("getStreamLength"); -+static const AVal av_ReceiveCheckPublicStatus = AVC("ReceiveCheckPublicStatus"); - - /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */ - static int -@@ -2341,6 +2399,11 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - AVal method; - double txn; - int ret = 0, nRes; -+ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc, **params = NULL; -+ char *host = r->Link.hostname.av_len ? r->Link.hostname.av_val : ""; -+ char *pageUrl = r->Link.pageUrl.av_len ? r->Link.pageUrl.av_val : ""; -+ int param_count; -+ AVal av_Command, av_Response; - if (body[0] != 0x02) /* make sure it is a string method name we start with */ - { - RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet", -@@ -2402,23 +2465,137 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - RTMP_SendServerBW(r); - RTMP_SendCtrl(r, 3, 0, 300); - } -- RTMP_SendCreateStream(r); -- -- if (!(r->Link.protocol & RTMP_FEATURE_WRITE)) -- { -- /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */ -- if (r->Link.usherToken.av_len) -- SendUsherToken(r, &r->Link.usherToken); -- /* Send the FCSubscribe if live stream or if subscribepath is set */ -- if (r->Link.subscribepath.av_len) -- SendFCSubscribe(r, &r->Link.subscribepath); -- else if (r->Link.lFlags & RTMP_LF_LIVE) -- SendFCSubscribe(r, &r->Link.playpath); -- } -- } -+ if (strstr(host, "tv-stream.to") || strstr(pageUrl, "tv-stream.to")) -+ { -+ static char auth[] = {'h', 0xC2, 0xA7, '4', 'j', 'h', 'H', '4', '3', 'd'}; -+ AVal av_auth; -+ SAVC(requestAccess); -+ av_auth.av_val = auth; -+ av_auth.av_len = sizeof (auth); -+ -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_requestAccess); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeString(enc, pend, &av_auth); -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ SendInvoke(r, &av_Command, FALSE); -+ -+ SAVC(getConnectionCount); -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_getConnectionCount); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ SendInvoke(r, &av_Command, FALSE); -+ -+ SendGetStreamLength(r); -+ } -+ else if (strstr(host, "jampo.com.ua") || strstr(pageUrl, "jampo.com.ua")) -+ { -+ SendGetStreamLength(r); -+ } -+ else if (strstr(host, "streamscene.cc") || strstr(pageUrl, "streamscene.cc") -+ || strstr(host, "tsboard.tv") || strstr(pageUrl, "teamstream.in")) -+ { -+ SAVC(r); -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_r); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ SendInvoke(r, &av_Command, FALSE); -+ -+ SendGetStreamLength(r); -+ } -+ else if (strstr(host, "chaturbate.com") || strstr(pageUrl, "chaturbate.com")) -+ { -+ AVal av_ModelName; -+ SAVC(CheckPublicStatus); -+ -+ if (strlen(pageUrl) > 7) -+ { -+ strsplit(pageUrl + 7, FALSE, '/', ¶ms); -+ av_ModelName.av_val = params[1]; -+ av_ModelName.av_len = strlen(params[1]); -+ -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_CheckPublicStatus); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeString(enc, pend, &av_ModelName); -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ -+ SendInvoke(r, &av_Command, FALSE); -+ } -+ else -+ { -+ RTMP_Log(RTMP_LOGERROR, "you must specify the pageUrl"); -+ RTMP_Close(r); -+ } -+ } -+ /* Weeb.tv specific authentication */ -+ else if (r->Link.WeebToken.av_len) -+ { -+ AVal av_Token, av_Username, av_Password; -+ SAVC(determineAccess); -+ -+ param_count = strsplit(r->Link.WeebToken.av_val, FALSE, ';', ¶ms); -+ if (param_count >= 1) -+ { -+ av_Token.av_val = params[0]; -+ av_Token.av_len = strlen(params[0]); -+ } -+ if (param_count >= 2) -+ { -+ av_Username.av_val = params[1]; -+ av_Username.av_len = strlen(params[1]); -+ } -+ if (param_count >= 3) -+ { -+ av_Password.av_val = params[2]; -+ av_Password.av_len = strlen(params[2]); -+ } -+ -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_determineAccess); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeString(enc, pend, &av_Token); -+ enc = AMF_EncodeString(enc, pend, &av_Username); -+ enc = AMF_EncodeString(enc, pend, &av_Password); -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ -+ RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", r->Link.WeebToken.av_val); -+ SendInvoke(r, &av_Command, FALSE); -+ } -+ else -+ RTMP_SendCreateStream(r); -+ } -+ else if (AVMATCH(&methodInvoked, &av_getStreamLength)) -+ { -+ RTMP_SendCreateStream(r); -+ } - else if (AVMATCH(&methodInvoked, &av_createStream)) -- { -- r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -+ { -+ r->m_stream_id = (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -+ -+ if (!(r->Link.protocol & RTMP_FEATURE_WRITE)) -+ { -+ /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */ -+ if (r->Link.usherToken.av_len) -+ SendUsherToken(r, &r->Link.usherToken); -+ /* Send the FCSubscribe if live stream or if subscribepath is set */ -+ if (r->Link.subscribepath.av_len) -+ SendFCSubscribe(r, &r->Link.subscribepath); -+ else if ((r->Link.lFlags & RTMP_LF_LIVE) && (!r->Link.WeebToken.av_len)) -+ SendFCSubscribe(r, &r->Link.playpath); -+ } - - if (r->Link.protocol & RTMP_FEATURE_WRITE) - { -@@ -2441,7 +2618,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - } - else if (AVMATCH(&method, &av_onBWDone)) - { -- if (!r->m_nBWCheckCounter) -+ if (!r->m_nBWCheckCounter) - SendCheckBW(r); - } - else if (AVMATCH(&method, &av_onFCSubscribe)) -@@ -2457,7 +2634,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - { - SendPong(r, txn); - } -- else if (AVMATCH(&method, &av__onbwcheck)) -+ else if (AVMATCH(&method, &av__onbwcheck) || AVMATCH(&method, &av_onBWCheck)) - { - SendCheckBWResult(r, txn); - } -@@ -2473,20 +2650,63 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - } - else if (AVMATCH(&method, &av__error)) - { -- RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); -+ double code = 0; -+ unsigned int parsedPort; -+ AMFObject obj2; -+ AMFObjectProperty p; -+ AVal redirect; -+ SAVC(ex); -+ SAVC(redirect); -+ -+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); -+ if (RTMP_FindFirstMatchingProperty(&obj2, &av_ex, &p)) -+ { -+ AMFProp_GetObject(&p, &obj2); -+ if (RTMP_FindFirstMatchingProperty(&obj2, &av_code, &p)) -+ code = AMFProp_GetNumber(&p); -+ if (code == 302 && RTMP_FindFirstMatchingProperty(&obj2, &av_redirect, &p)) -+ { -+ AMFProp_GetString(&p, &redirect); -+ r->Link.redirected = TRUE; -+ -+ char *url = malloc(redirect.av_len + sizeof ("/playpath")); -+ strncpy(url, redirect.av_val, redirect.av_len); -+ url[redirect.av_len] = '\0'; -+ r->Link.tcUrl.av_val = url; -+ r->Link.tcUrl.av_len = redirect.av_len; -+ strcat(url, "/playpath"); -+ RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname, &parsedPort, &r->Link.playpath0, &r->Link.app); -+ r->Link.port = parsedPort; -+ } -+ } -+ if (r->Link.redirected) -+ RTMP_Log(RTMP_LOGINFO, "rtmp server sent redirect"); -+ else -+ RTMP_Log(RTMP_LOGERROR, "rtmp server sent error"); - } - else if (AVMATCH(&method, &av_close)) - { -- RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); -- RTMP_Close(r); -+ if (r->Link.redirected) -+ { -+ RTMP_Log(RTMP_LOGINFO, "trying to connect with redirected url"); -+ RTMP_Close(r); -+ r->Link.redirected = FALSE; -+ RTMP_Connect(r, NULL); -+ } -+ else -+ { -+ RTMP_Log(RTMP_LOGERROR, "rtmp server requested close"); -+ RTMP_Close(r); -+ } - } - else if (AVMATCH(&method, &av_onStatus)) - { - AMFObject obj2; -- AVal code, level; -+ AVal code, level, description; - AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2); - AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code); - AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level); -+ AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description); - - RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val); - if (AVMATCH(&code, &av_NetStream_Failed) -@@ -2550,6 +2770,45 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - r->m_pausing = 3; - } - } -+ -+ else if (AVMATCH(&code, &av_NetConnection_confStream)) -+ { -+#ifdef CRYPTO -+ static const char hexdig[] = "0123456789abcdef"; -+ SAVC(cf_stream); -+ int i; -+ char hash_hex[33] = {0}; -+ unsigned char hash[16]; -+ AVal auth; -+ param_count = strsplit(description.av_val, description.av_len, ':', ¶ms); -+ if (param_count >= 3) -+ { -+ char *buf = malloc(strlen(params[0]) + r->Link.playpath.av_len + 1); -+ strcpy(buf, params[0]); -+ strncat(buf, r->Link.playpath.av_val, r->Link.playpath.av_len); -+ md5_hash((unsigned char *) buf, strlen(buf), hash); -+ for (i = 0; i < 16; i++) -+ { -+ hash_hex[i * 2] = hexdig[0x0f & (hash[i] >> 4)]; -+ hash_hex[i * 2 + 1] = hexdig[0x0f & (hash[i])]; -+ } -+ auth.av_val = &hash_hex[atoi(params[1]) - 1]; -+ auth.av_len = atoi(params[2]); -+ RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %.*s", auth.av_len, auth.av_val); -+ -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_cf_stream); -+ enc = AMF_EncodeNumber(enc, pend, txn); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeString(enc, pend, &auth); -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ -+ SendInvoke(r, &av_Command, FALSE); -+ free(buf); -+ } -+#endif -+ } - } - else if (AVMATCH(&method, &av_playlist_ready)) - { -@@ -2563,6 +2822,74 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) - } - } - } -+ else if (AVMATCH(&method, &av_verifyClient)) -+ { -+ double VerificationNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); -+ RTMP_Log(RTMP_LOGDEBUG, "VerificationNumber: %.2f", VerificationNumber); -+ -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av__result); -+ enc = AMF_EncodeNumber(enc, pend, txn); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeNumber(enc, pend, exp(atan(sqrt(VerificationNumber))) + 1); -+ av_Response.av_val = pbuf; -+ av_Response.av_len = enc - pbuf; -+ -+ AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE); -+ AMF_Dump(&obj); -+ SendInvoke(r, &av_Response, FALSE); -+ } -+ else if (AVMATCH(&method, &av_sendStatus)) -+ { -+ if (r->Link.WeebToken.av_len) -+ { -+ AVal av_Authorized = AVC("User.hasAccess"); -+ AVal av_TransferLimit = AVC("User.noPremium.limited"); -+ AVal av_UserLimit = AVC("User.noPremium.tooManyUsers"); -+ AVal av_TimeLeft = AVC("timeLeft"); -+ AVal av_Status, av_ReconnectionTime; -+ -+ AMFObject Status; -+ AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &Status); -+ AMFProp_GetString(AMF_GetProp(&Status, &av_code, -1), &av_Status); -+ RTMP_Log(RTMP_LOGINFO, "%.*s", av_Status.av_len, av_Status.av_val); -+ if (AVMATCH(&av_Status, &av_Authorized)) -+ { -+ RTMP_Log(RTMP_LOGINFO, "Weeb.tv authentication successful"); -+ RTMP_SendCreateStream(r); -+ } -+ else if (AVMATCH(&av_Status, &av_UserLimit)) -+ { -+ RTMP_Log(RTMP_LOGINFO, "No free slots available"); -+ RTMP_Close(r); -+ } -+ else if (AVMATCH(&av_Status, &av_TransferLimit)) -+ { -+ AMFProp_GetString(AMF_GetProp(&Status, &av_TimeLeft, -1), &av_ReconnectionTime); -+ RTMP_Log(RTMP_LOGINFO, "Viewing limit exceeded. try again in %.*s minutes.", av_ReconnectionTime.av_len, av_ReconnectionTime.av_val); -+ RTMP_Close(r); -+ } -+ } -+ } -+ else if (AVMATCH(&method, &av_ReceiveCheckPublicStatus)) -+ { -+ AVal Status; -+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &Status); -+ strsplit(Status.av_val, Status.av_len, ',', ¶ms); -+ if (strcmp(params[0], "0") == 0) -+ { -+ RTMP_Log(RTMP_LOGINFO, "Model status is %s", params[1]); -+ RTMP_Close(r); -+ } -+ else -+ { -+ AVal Playpath; -+ Playpath.av_val = params[1]; -+ Playpath.av_len = strlen(params[1]); -+ RTMP_ParsePlaypath(&Playpath, &r->Link.playpath); -+ RTMP_SendCreateStream(r); -+ } -+ } - else - { - -@@ -2748,7 +3075,7 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet) - unsigned int tmp; - if (packet->m_body && packet->m_nBodySize >= 2) - nType = AMF_DecodeInt16(packet->m_body); -- RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType, -+ RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl, type: %d, len: %d", __FUNCTION__, nType, - packet->m_nBodySize); - /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */ - -@@ -2856,15 +3183,15 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet) - RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__); - if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01) - { -- RTMP_Log(RTMP_LOGERROR, -- "%s: SWFVerification Type %d request not supported! Patches welcome...", -- __FUNCTION__, packet->m_body[2]); -+ RTMP_Log(RTMP_LOGERROR, -+ "%s: SWFVerification Type %d request not supported, attempting to use SWFVerification Type 1! Patches welcome...", -+ __FUNCTION__, packet->m_body[2]); - } - #ifdef CRYPTO - /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */ - - /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */ -- else if (r->Link.SWFSize) -+ if (r->Link.SWFSize) - { - RTMP_SendCtrl(r, 0x1B, 0, 0); - } -@@ -3142,8 +3469,18 @@ HandShake(RTMP *r, int FP9HandShake) - serversig[4], serversig[5], serversig[6], serversig[7]); - - /* 2nd part of handshake */ -- if (!WriteN(r, serversig, RTMP_SIG_SIZE)) -- return FALSE; -+ if (r->Link.CombineConnectPacket) -+ { -+ char *HandshakeResponse = malloc(RTMP_SIG_SIZE); -+ memcpy(HandshakeResponse, (char *) serversig, RTMP_SIG_SIZE); -+ r->Link.HandshakeResponse.av_val = HandshakeResponse; -+ r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE; -+ } -+ else -+ { -+ if (!WriteN(r, (char *) serversig, RTMP_SIG_SIZE)) -+ return FALSE; -+ } - - if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE) - return FALSE; -@@ -3709,12 +4046,11 @@ HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len) - char hbuf[512]; - int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n" - "Host: %.*s:%d\r\n" -- "Accept: */*\r\n" -- "User-Agent: Shockwave Flash\n" -- "Connection: Keep-Alive\n" -+ "User-Agent: Shockwave Flash\r\n" -+ "Connection: Keep-Alive\r\n" - "Cache-Control: no-cache\r\n" -- "Content-type: application/x-fcs\r\n" -- "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd], -+ "Content-Type: application/x-fcs\r\n" -+ "Content-Length: %d\r\n\r\n", RTMPT_cmds[cmd], - r->m_clientID.av_val ? r->m_clientID.av_val : "", - r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val, - r->Link.port, len); -@@ -3749,6 +4085,14 @@ HTTP_read(RTMP *r, int fill) - if (!ptr) - return -1; - ptr += 4; -+ int resplen = r->m_sb.sb_size - (ptr - r->m_sb.sb_start); -+ if (hlen < 4096) -+ while (resplen < hlen) -+ { -+ if (RTMPSockBuf_Fill(&r->m_sb) == -1) -+ return -1; -+ resplen = r->m_sb.sb_size - (ptr - r->m_sb.sb_start); -+ } - r->m_sb.sb_size -= ptr - r->m_sb.sb_start; - r->m_sb.sb_start = ptr; - r->m_unackd--; -@@ -4301,13 +4645,21 @@ fail: - r->m_read.status = nRead; - goto fail; - } -- /* buffer overflow, fix buffer and give up */ -- if (r->m_read.buf < mybuf || r->m_read.buf > end) { -- mybuf = realloc(mybuf, cnt + nRead); -- memcpy(mybuf+cnt, r->m_read.buf, nRead); -- r->m_read.buf = mybuf+cnt+nRead; -- break; -- } -+ /* buffer overflow, fix buffer and give up */ -+ if (r->m_read.buf < mybuf || r->m_read.buf > end) -+ { -+ if (!cnt) -+ { -+ mybuf = realloc(mybuf, sizeof (flvHeader) + cnt + nRead); -+ memcpy(mybuf, flvHeader, sizeof (flvHeader)); -+ cnt += sizeof (flvHeader); -+ } -+ else -+ mybuf = realloc(mybuf, cnt + nRead); -+ memcpy(mybuf + cnt, r->m_read.buf, nRead); -+ r->m_read.buf = mybuf + cnt + nRead; -+ break; -+ } - cnt += nRead; - r->m_read.buf += nRead; - r->m_read.buflen -= nRead; -@@ -4458,3 +4810,90 @@ RTMP_Write(RTMP *r, const char *buf, int size) - } - return size+s2; - } -+ -+static int -+SendInvoke(RTMP *r, AVal *Command, int queue) -+{ -+ RTMPPacket packet; -+ char pbuf[512], *enc; -+ -+ packet.m_nChannel = 0x03; /* control channel (invoke) */ -+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -+ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -+ packet.m_nTimeStamp = 0; -+ packet.m_nInfoField2 = 0; -+ packet.m_hasAbsTimestamp = 0; -+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -+ -+ enc = packet.m_body; -+ if (Command->av_len) -+ { -+ memcpy(enc, Command->av_val, Command->av_len); -+ enc += Command->av_len; -+ } -+ else -+ return FALSE; -+ packet.m_nBodySize = enc - packet.m_body; -+ -+ return RTMP_SendPacket(r, &packet, queue); -+} -+ -+static int -+strsplit(char *src, int srclen, char delim, char ***params) -+{ -+ char *sptr, *srcbeg, *srcend, *dstr; -+ int count = 1, i = 0, len = 0; -+ -+ if (src == NULL) -+ return 0; -+ if (!srclen) -+ srclen = strlen(src); -+ srcbeg = src; -+ srcend = srcbeg + srclen; -+ sptr = srcbeg; -+ -+ /* count the delimiters */ -+ while (sptr < srcend) -+ { -+ if (*sptr++ == delim) -+ count++; -+ } -+ sptr = srcbeg; -+ *params = calloc(count, sizeof (size_t)); -+ char **param = *params; -+ -+ for (i = 0; i < (count - 1); i++) -+ { -+ dstr = strchr(sptr, delim); -+ len = dstr - sptr; -+ param[i] = calloc(len + 1, sizeof (char)); -+ strncpy(param[i], sptr, len); -+ sptr += len + 1; -+ } -+ -+ /* copy the last string */ -+ if (sptr <= srcend) -+ { -+ len = srclen - (sptr - srcbeg); -+ param[i] = calloc(len + 1, sizeof (char)); -+ strncpy(param[i], sptr, len); -+ } -+ return count; -+} -+ -+static int -+SendGetStreamLength(RTMP *r) -+{ -+ char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc; -+ AVal av_Command; -+ -+ enc = pbuf; -+ enc = AMF_EncodeString(enc, pend, &av_getStreamLength); -+ enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeString(enc, pend, &r->Link.playpath); -+ av_Command.av_val = pbuf; -+ av_Command.av_len = enc - pbuf; -+ -+ return SendInvoke(r, &av_Command, TRUE); -+} -diff --git a/librtmp/rtmp.h b/librtmp/rtmp.h -index 6b2ae5b..411b488 100644 ---- a/librtmp/rtmp.h -+++ b/librtmp/rtmp.h -@@ -150,12 +150,14 @@ extern "C" - AVal playpath; /* passed in explicitly */ - AVal tcUrl; - AVal swfUrl; -+ AVal swfHash; - AVal pageUrl; - AVal app; - AVal auth; - AVal flashVer; - AVal subscribepath; - AVal usherToken; -+ AVal WeebToken; - AVal token; - AMFObject extras; - int edepth; -@@ -172,9 +174,15 @@ extern "C" - int lFlags; - - int swfAge; -+ int swfSize; - - int protocol; -+ int ConnectPacket; -+ int CombineConnectPacket; -+ int redirected; - int timeout; /* connection timeout in seconds */ -+ AVal Extras; -+ AVal HandshakeResponse; - - unsigned short socksport; - unsigned short port; -@@ -299,6 +307,7 @@ extern "C" - AVal *flashVer, - AVal *subscribepath, - AVal *usherToken, -+ AVal *WeebToken, - int dStart, - int dStop, int bLiveStream, long int timeout); - -diff --git a/librtmp/rtmp_sys.h b/librtmp/rtmp_sys.h -index c3fd4a6..1bfb562 100644 ---- a/librtmp/rtmp_sys.h -+++ b/librtmp/rtmp_sys.h -@@ -64,6 +64,7 @@ - #include <polarssl/net.h> - #include <polarssl/ssl.h> - #include <polarssl/havege.h> -+#include <polarssl/md5.h> - typedef struct tls_ctx { - havege_state hs; - ssl_session ssn; -@@ -71,7 +72,7 @@ typedef struct tls_ctx { - #define TLS_CTX tls_ctx * - #define TLS_client(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\ - ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\ -- ssl_set_rng(s, havege_rand, &ctx->hs);\ -+ ssl_set_rng(s, havege_random, &ctx->hs);\ - ssl_set_ciphersuites(s, ssl_default_ciphersuites);\ - ssl_set_session(s, 1, 600, &ctx->ssn) - #define TLS_setfd(s,fd) ssl_set_bio(s, net_recv, &fd, net_send, &fd) -@@ -80,6 +81,7 @@ typedef struct tls_ctx { - #define TLS_write(s,b,l) ssl_write(s,(unsigned char *)b,l) - #define TLS_shutdown(s) ssl_close_notify(s) - #define TLS_close(s) ssl_free(s); free(s) -+#define md5_hash(i, ilen, o) md5(i, ilen, o) - - #elif defined(USE_GNUTLS) - #include <gnutls/gnutls.h> -@@ -95,6 +97,8 @@ typedef struct tls_ctx { - #define TLS_write(s,b,l) gnutls_record_send(s,b,l) - #define TLS_shutdown(s) gnutls_bye(s, GNUTLS_SHUT_RDWR) - #define TLS_close(s) gnutls_deinit(s) -+#define md5_hash(i, ilen, o) gnutls_digest_algorithm_t algorithm = GNUTLS_DIG_MD5;\ -+ gnutls_hash_fast(algorithm, i, ilen, o); - - #else /* USE_OPENSSL */ - #define TLS_CTX SSL_CTX * -@@ -105,6 +109,7 @@ typedef struct tls_ctx { - #define TLS_write(s,b,l) SSL_write(s,b,l) - #define TLS_shutdown(s) SSL_shutdown(s) - #define TLS_close(s) SSL_free(s) -+#define md5_hash(i, ilen, o) MD5(i, ilen, o) - - #endif - #endif -diff --git a/rtmpdump.c b/rtmpdump.c -index e52f7d4..7bb0890 100644 ---- a/rtmpdump.c -+++ b/rtmpdump.c -@@ -701,6 +701,8 @@ void usage(char *prog) - RTMP_LogPrintf - ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n"); - RTMP_LogPrintf -+ ("--weeb|-J string Authentication token for weeb.tv servers\n"); -+ RTMP_LogPrintf - ("--hashes|-# Display progress with hashes, not with the byte counter\n"); - RTMP_LogPrintf - ("--buffer|-b Buffer time in milliseconds (default: %u)\n", -@@ -747,7 +749,8 @@ main(int argc, char **argv) - AVal hostname = { 0, 0 }; - AVal playpath = { 0, 0 }; - AVal subscribepath = { 0, 0 }; -- AVal usherToken = { 0, 0 }; //Justin.tv auth token -+ AVal usherToken = { 0, 0 }; // Justin.tv auth token -+ AVal WeebToken = { 0, 0 }; // Weeb.tv auth token - int port = -1; - int protocol = RTMP_PROTOCOL_UNDEFINED; - int retries = 0; -@@ -852,12 +855,13 @@ main(int argc, char **argv) - {"quiet", 0, NULL, 'q'}, - {"verbose", 0, NULL, 'V'}, - {"jtv", 1, NULL, 'j'}, -+ {"weeb", 1, NULL, 'J'}, - {0, 0, 0, 0} - }; - - while ((opt = - getopt_long(argc, argv, -- "hVveqzRr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:", -+ "hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:J:", - longopts, NULL)) != -1) - { - switch (opt) -@@ -1070,6 +1074,9 @@ main(int argc, char **argv) - case 'j': - STR2AVAL(usherToken, optarg); - break; -+ case 'J': -+ STR2AVAL(WeebToken, optarg); -+ break; - default: - RTMP_LogPrintf("unknown option: %c\n", opt); - usage(argv[0]); -@@ -1161,14 +1168,14 @@ main(int argc, char **argv) - - if (tcUrl.av_len == 0) - { -- tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) + -- hostname.av_len + app.av_len + sizeof("://:65535/"); -+ tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) + -+ hostname.av_len + app.av_len + sizeof ("://:65535/"); - tcUrl.av_val = (char *) malloc(tcUrl.av_len); -- if (!tcUrl.av_val) -- return RD_FAILED; -+ if (!tcUrl.av_val) -+ return RD_FAILED; - tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s", -- RTMPProtocolStringsLower[protocol], hostname.av_len, -- hostname.av_val, port, app.av_len, app.av_val); -+ RTMPProtocolStringsLower[protocol], hostname.av_len, -+ hostname.av_val, port, app.av_len, app.av_val); - } - - int first = 1; -@@ -1187,7 +1194,7 @@ main(int argc, char **argv) - - RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath, - &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize, -- &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout); -+ &flashVer, &subscribepath, &usherToken, &WeebToken, dSeek, dStopOffset, bLiveStream, timeout); - - /* Try to keep the stream moving if it pauses on us */ - if (!bLiveStream && !bRealtimeStream && !(protocol & RTMP_FEATURE_HTTP)) -diff --git a/rtmpgw.c b/rtmpgw.c -index 0cf56bb..cd4396d 100644 ---- a/rtmpgw.c -+++ b/rtmpgw.c -@@ -95,7 +95,8 @@ typedef struct - AVal flashVer; - AVal token; - AVal subscribepath; -- AVal usherToken; //Justin.tv auth token -+ AVal usherToken; // Justin.tv auth token -+ AVal WeebToken; // Weeb.tv auth token - AVal sockshost; - AMFObject extras; - int edepth; -@@ -553,7 +554,7 @@ void processTCPrequest(STREAMING_SERVER * server, // server socket and state (ou - RTMP_Init(&rtmp); - RTMP_SetBufferMS(&rtmp, req.bufferTime); - RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost, -- &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, dSeek, req.dStopOffset, -+ &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, &req.usherToken, &req.WeebToken, dSeek, req.dStopOffset, - req.bLiveStream, req.timeout); - /* backward compatibility, we always sent this as true before */ - if (req.auth.av_len) -@@ -957,6 +958,9 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req) - case 'j': - STR2AVAL(req->usherToken, arg); - break; -+ case 'J': -+ STR2AVAL(req->WeebToken, arg); -+ break; - default: - RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg); - return FALSE; -@@ -1028,6 +1032,7 @@ main(int argc, char **argv) - {"quiet", 0, NULL, 'q'}, - {"verbose", 0, NULL, 'V'}, - {"jtv", 1, NULL, 'j'}, -+ {"weeb", 1, NULL, 'J'}, - {0, 0, 0, 0} - }; - -@@ -1040,7 +1045,7 @@ main(int argc, char **argv) - - while ((opt = - getopt_long(argc, argv, -- "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:", longopts, -+ "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:S:j:J:", longopts, - NULL)) != -1) - { - switch (opt) -@@ -1103,6 +1108,8 @@ main(int argc, char **argv) - RTMP_LogPrintf - ("--jtv|-j JSON Authentication token for Justin.tv legacy servers\n"); - RTMP_LogPrintf -+ ("--weeb|-J string Authentication token for weeb.tv servers\n"); -+ RTMP_LogPrintf - ("--buffer|-b Buffer time in milliseconds (default: %u)\n\n", - defaultRTMPRequest.bufferTime); - -diff --git a/rtmpsrv.c b/rtmpsrv.c -index 9aa62f3..9ec8f23 100644 ---- a/rtmpsrv.c -+++ b/rtmpsrv.c -@@ -96,9 +96,20 @@ STREAMING_SERVER *rtmpServer = 0; // server structure pointer - STREAMING_SERVER *startStreaming(const char *address, int port); - void stopStreaming(STREAMING_SERVER * server); - void AVreplace(AVal *src, const AVal *orig, const AVal *repl); -+char *strreplace(char *srcstr, int srclen, char *orig, char *repl); -+int file_exists(const char *fname); -+int SendCheckBWResponse(RTMP *r, int oldMethodType, int onBWDoneInit); -+AVal AVcopy(AVal src); -+AVal StripParams(AVal *src); - - static const AVal av_dquote = AVC("\""); - static const AVal av_escdquote = AVC("\\\""); -+#ifdef WIN32 -+static const AVal av_caret = AVC("^"); -+static const AVal av_esccaret = AVC("^^"); -+static const AVal av_pipe = AVC("|"); -+static const AVal av_escpipe = AVC("^|"); -+#endif - - typedef struct - { -@@ -167,6 +178,10 @@ SAVC(level); - SAVC(code); - SAVC(description); - SAVC(secureToken); -+SAVC(_checkbw); -+SAVC(_onbwdone); -+SAVC(checkBandwidth); -+SAVC(onBWDone); - - static int - SendConnectResult(RTMP *r, double txn) -@@ -190,7 +205,7 @@ SendConnectResult(RTMP *r, double txn) - enc = AMF_EncodeNumber(enc, pend, txn); - *enc++ = AMF_OBJECT; - -- STR2AVAL(av, "FMS/3,5,1,525"); -+ STR2AVAL(av, "FMS/3,5,7,7009"); - enc = AMF_EncodeNamedString(enc, pend, &av_fmsVer, &av); - enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 31.0); - enc = AMF_EncodeNamedNumber(enc, pend, &av_mode, 1.0); -@@ -212,7 +227,7 @@ SendConnectResult(RTMP *r, double txn) - enc = AMF_EncodeNamedString(enc, pend, &av_secureToken, &av); - #endif - STR2AVAL(p.p_name, "version"); -- STR2AVAL(p.p_vu.p_aval, "3,5,1,525"); -+ STR2AVAL(p.p_vu.p_aval, "3,5,7,7009"); - p.p_type = AMF_STRING; - obj.o_num = 1; - obj.o_props = &p; -@@ -268,7 +283,7 @@ static int - SendPlayStart(RTMP *r) - { - RTMPPacket packet; -- char pbuf[512], *pend = pbuf+sizeof(pbuf); -+ char pbuf[1024], *pend = pbuf + sizeof (pbuf); - - packet.m_nChannel = 0x03; // control channel (invoke) - packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -@@ -300,7 +315,7 @@ static int - SendPlayStop(RTMP *r) - { - RTMPPacket packet; -- char pbuf[512], *pend = pbuf+sizeof(pbuf); -+ char pbuf[1024], *pend = pbuf + sizeof (pbuf); - - packet.m_nChannel = 0x03; // control channel (invoke) - packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ -@@ -328,6 +343,49 @@ SendPlayStop(RTMP *r) - return RTMP_SendPacket(r, &packet, FALSE); - } - -+int -+SendCheckBWResponse(RTMP *r, int oldMethodType, int onBWDoneInit) -+{ -+ RTMPPacket packet; -+ char pbuf[256], *pend = pbuf + sizeof (pbuf); -+ char *enc; -+ -+ packet.m_nChannel = 0x03; /* control channel (invoke) */ -+ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; -+ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; -+ packet.m_nTimeStamp = 0; -+ packet.m_nInfoField2 = 0; -+ packet.m_hasAbsTimestamp = 0; -+ packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; -+ -+ enc = packet.m_body; -+ if (oldMethodType) -+ { -+ enc = AMF_EncodeString(enc, pend, &av__onbwdone); -+ enc = AMF_EncodeNumber(enc, pend, 0); -+ *enc++ = AMF_NULL; -+ enc = AMF_EncodeNumber(enc, pend, 10240); -+ enc = AMF_EncodeNumber(enc, pend, 10240); -+ } -+ else -+ { -+ enc = AMF_EncodeString(enc, pend, &av_onBWDone); -+ enc = AMF_EncodeNumber(enc, pend, 0); -+ *enc++ = AMF_NULL; -+ if (!onBWDoneInit) -+ { -+ enc = AMF_EncodeNumber(enc, pend, 10240); -+ enc = AMF_EncodeNumber(enc, pend, 10240); -+ enc = AMF_EncodeNumber(enc, pend, 0); -+ enc = AMF_EncodeNumber(enc, pend, 0); -+ } -+ } -+ -+ packet.m_nBodySize = enc - packet.m_body; -+ -+ return RTMP_SendPacket(r, &packet, FALSE); -+} -+ - static void - spawn_dumper(int argc, AVal *av, char *cmd) - { -@@ -568,6 +626,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - server->arglen += countAMF(&r->Link.extras, &server->argc); - } - SendConnectResult(r, txn); -+ SendCheckBWResponse(r, FALSE, TRUE); - } - else if (AVMATCH(&method, &av_createStream)) - { -@@ -582,10 +641,22 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - AVal usherToken; - AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken); - AVreplace(&usherToken, &av_dquote, &av_escdquote); -+#ifdef WIN32 -+ AVreplace(&usherToken, &av_caret, &av_esccaret); -+ AVreplace(&usherToken, &av_pipe, &av_escpipe); -+#endif - server->arglen += 6 + usherToken.av_len; - server->argc += 2; - r->Link.usherToken = usherToken; - } -+ else if (AVMATCH(&method, &av__checkbw)) -+ { -+ SendCheckBWResponse(r, TRUE, FALSE); -+ } -+ else if (AVMATCH(&method, &av_checkBandwidth)) -+ { -+ SendCheckBWResponse(r, FALSE, FALSE); -+ } - else if (AVMATCH(&method, &av_play)) - { - char *file, *p, *q, *cmd, *ptr; -@@ -599,6 +670,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - if (obj.o_num > 5) - r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5)); - */ -+ double StartFlag = 0; -+ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4); -+ if (!(Start->p_type == AMF_INVALID)) -+ StartFlag = AMFProp_GetNumber(Start); -+ r->Link.app = AVcopy(r->Link.app); -+ if (StartFlag == -1000 || strstr(r->Link.app.av_val, "live")) -+ { -+ StartFlag = -1000; -+ server->arglen += 7; -+ server->argc += 1; -+ } - if (r->Link.tcUrl.av_len) - { - len = server->arglen + r->Link.playpath.av_len + 4 + -@@ -616,6 +698,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - argv[argc].av_val = ptr + 1; - argv[argc++].av_len = 2; - argv[argc].av_val = ptr + 5; -+ r->Link.tcUrl = StripParams(&r->Link.tcUrl); - ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val); - argv[argc++].av_len = r->Link.tcUrl.av_len; - -@@ -640,6 +723,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - argv[argc].av_val = ptr + 1; - argv[argc++].av_len = 2; - argv[argc].av_val = ptr + 5; -+ r->Link.swfUrl = StripParams(&r->Link.swfUrl); - ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val); - argv[argc++].av_len = r->Link.swfUrl.av_len; - } -@@ -662,10 +746,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - r->Link.usherToken.av_val = NULL; - r->Link.usherToken.av_len = 0; - } -- if (r->Link.extras.o_num) { -- ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); -- AMF_Reset(&r->Link.extras); -- } -+ if (StartFlag == -1000) -+ { -+ argv[argc].av_val = ptr + 1; -+ argv[argc++].av_len = 6; -+ ptr += sprintf(ptr, " --live"); -+ } -+ if (r->Link.extras.o_num) -+ { -+ ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc); -+ AMF_Reset(&r->Link.extras); -+ } - argv[argc].av_val = ptr + 1; - argv[argc++].av_len = 2; - argv[argc].av_val = ptr + 5; -@@ -673,7 +764,13 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - r->Link.playpath.av_len, r->Link.playpath.av_val); - argv[argc++].av_len = r->Link.playpath.av_len; - -- av = r->Link.playpath; -+ if (r->Link.playpath.av_len) -+ av = r->Link.playpath; -+ else -+ { -+ av.av_val = "file"; -+ av.av_len = 4; -+ } - /* strip trailing URL parameters */ - q = memchr(av.av_val, '?', av.av_len); - if (q) -@@ -725,7 +822,30 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - argv[argc++].av_len = 2; - argv[argc].av_val = file; - argv[argc].av_len = av.av_len; -- ptr += sprintf(ptr, " -o %s", file); -+#ifdef VLC -+ char *vlc; -+ int didAlloc = FALSE; -+ -+ if (getenv("VLC")) -+ vlc = getenv("VLC"); -+ else if (getenv("ProgramFiles")) -+ { -+ vlc = malloc(512 * sizeof (char)); -+ didAlloc = TRUE; -+ char *ProgramFiles = getenv("ProgramFiles"); -+ sprintf(vlc, "%s%s", ProgramFiles, " (x86)\\VideoLAN\\VLC\\vlc.exe"); -+ if (!file_exists(vlc)) -+ sprintf(vlc, "%s%s", ProgramFiles, "\\VideoLAN\\VLC\\vlc.exe"); -+ } -+ else -+ vlc = "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe"; -+ -+ ptr += sprintf(ptr, " | %s -", vlc); -+ if (didAlloc) -+ free(vlc); -+#else -+ ptr += sprintf(ptr, " -o %s", file); -+#endif - now = RTMP_GetTime(); - if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename)) - { -@@ -739,7 +859,23 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int - server->filetime = now; - free(server->filename.av_val); - server->filename = argv[argc++]; -- spawn_dumper(argc, argv, cmd); -+#ifdef VLC -+ FILE *vlc_cmdfile = fopen("VLC.bat", "w"); -+ char *vlc_batchcmd = strreplace(cmd, 0, "%", "%%"); -+ fprintf(vlc_cmdfile, "%s\n", vlc_batchcmd); -+ fclose(vlc_cmdfile); -+ free(vlc_batchcmd); -+ spawn_dumper(argc, argv, "VLC.bat"); -+#else -+ spawn_dumper(argc, argv, cmd); -+#endif -+ -+#ifdef WIN32 -+ // Dump command to batch file -+ FILE *cmdfile = fopen("Command.bat", "a"); -+ fprintf(cmdfile, "%s\n", cmd); -+ fclose(cmdfile); -+#endif - } - - free(cmd); -@@ -1178,3 +1314,115 @@ AVreplace(AVal *src, const AVal *orig, const AVal *repl) - src->av_val = dest; - src->av_len = dptr - dest; - } -+ -+char * -+strreplace(char *srcstr, int srclen, char *orig, char *repl) -+{ -+ char *ptr = NULL, *sptr = srcstr; -+ int origlen = strlen(orig); -+ int repllen = strlen(repl); -+ if (!srclen) -+ srclen = strlen(srcstr); -+ char *srcend = srcstr + srclen; -+ int dstbuffer = srclen / origlen * repllen; -+ if (dstbuffer < srclen) -+ dstbuffer = srclen; -+ char *dststr = calloc(dstbuffer + 1, sizeof (char)); -+ char *dptr = dststr; -+ -+ if ((ptr = strstr(srcstr, orig))) -+ { -+ while (ptr < srcend && (ptr = strstr(sptr, orig))) -+ { -+ int len = ptr - sptr; -+ memcpy(dptr, sptr, len); -+ sptr += len + origlen; -+ dptr += len; -+ memcpy(dptr, repl, repllen); -+ dptr += repllen; -+ } -+ memcpy(dptr, sptr, srcend - sptr); -+ return dststr; -+ } -+ -+ memcpy(dststr, srcstr, srclen); -+ return dststr; -+} -+ -+AVal -+StripParams(AVal *src) -+{ -+ AVal str; -+ if (src->av_val) -+ { -+ str.av_val = calloc(src->av_len + 1, sizeof (char)); -+ strncpy(str.av_val, src->av_val, src->av_len); -+ str.av_len = src->av_len; -+ char *start = str.av_val; -+ char *end = start + str.av_len; -+ char *ptr = start; -+ -+ while (ptr < end) -+ { -+ if (*ptr == '?') -+ { -+ str.av_len = ptr - start; -+ break; -+ } -+ ptr++; -+ } -+ memset(start + str.av_len, 0, 1); -+ -+ char *dynamic = strstr(start, "[[DYNAMIC]]"); -+ if (dynamic) -+ { -+ dynamic -= 1; -+ memset(dynamic, 0, 1); -+ str.av_len = dynamic - start; -+ end = start + str.av_len; -+ } -+ -+ char *import = strstr(start, "[[IMPORT]]"); -+ if (import) -+ { -+ str.av_val = import + 11; -+ strcpy(start, "http://"); -+ str.av_val = strcat(start, str.av_val); -+ str.av_len = strlen(str.av_val); -+ } -+ return str; -+ } -+ str = *src; -+ return str; -+} -+ -+int -+file_exists(const char *fname) -+{ -+ FILE *file; -+ if ((file = fopen(fname, "r"))) -+ { -+ fclose(file); -+ return TRUE; -+ } -+ return FALSE; -+} -+ -+AVal -+AVcopy(AVal src) -+{ -+ AVal dst; -+ if (src.av_len) -+ { -+ dst.av_val = malloc(src.av_len + 1); -+ memcpy(dst.av_val, src.av_val, src.av_len); -+ dst.av_val[src.av_len] = '\0'; -+ dst.av_len = src.av_len; -+ } -+ else -+ { -+ dst.av_val = NULL; -+ dst.av_len = 0; -+ } -+ return dst; -+} -diff --git a/rtmpsuck.c b/rtmpsuck.c -index e886179..e80c686 100644 ---- a/rtmpsuck.c -+++ b/rtmpsuck.c -@@ -143,15 +143,18 @@ SAVC(onStatus); - SAVC(close); - static const AVal av_NetStream_Failed = AVC("NetStream.Failed"); - static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed"); --static const AVal av_NetStream_Play_StreamNotFound = --AVC("NetStream.Play.StreamNotFound"); --static const AVal av_NetConnection_Connect_InvalidApp = --AVC("NetConnection.Connect.InvalidApp"); -+static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound"); -+static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp"); - static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start"); - static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete"); - static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); -+static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken"); - - static const char *cst[] = { "client", "server" }; -+char *dumpAMF(AMFObject *obj, char *ptr); -+char *strreplace(char *srcstr, int srclen, char *orig, char *repl); -+AVal AVcopy(AVal src); -+AVal StripParams(AVal *src); - - // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' - int -@@ -198,26 +201,28 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - if (cobj.o_props[i].p_type == AMF_STRING) - { - pval = cobj.o_props[i].p_vu.p_aval; -- RTMP_LogPrintf("%.*s: %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val); -+ RTMP_LogPrintf("%10.*s : %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val); - } - if (AVMATCH(&pname, &av_app)) - { -- server->rc.Link.app = pval; -+ server->rc.Link.app = AVcopy(pval); - pval.av_val = NULL; - } - else if (AVMATCH(&pname, &av_flashVer)) - { -- server->rc.Link.flashVer = pval; -+ server->rc.Link.flashVer = AVcopy(pval); - pval.av_val = NULL; - } - else if (AVMATCH(&pname, &av_swfUrl)) - { - #ifdef CRYPTO - if (pval.av_val) -- RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize, -- (unsigned char *)server->rc.Link.SWFHash, 30); -+ { -+ AVal swfUrl = StripParams(&pval); -+ RTMP_HashSWF(swfUrl.av_val, &server->rc.Link.SWFSize, (unsigned char *) server->rc.Link.SWFHash, 30); -+ } - #endif -- server->rc.Link.swfUrl = pval; -+ server->rc.Link.swfUrl = AVcopy(pval); - pval.av_val = NULL; - } - else if (AVMATCH(&pname, &av_tcUrl)) -@@ -225,7 +230,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - char *r1 = NULL, *r2; - int len; - -- server->rc.Link.tcUrl = pval; -+ server->rc.Link.tcUrl = AVcopy(pval); - if ((pval.av_val[0] | 0x40) == 'r' && - (pval.av_val[1] | 0x40) == 't' && - (pval.av_val[2] | 0x40) == 'm' && -@@ -267,7 +272,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - } - else if (AVMATCH(&pname, &av_pageUrl)) - { -- server->rc.Link.pageUrl = pval; -+ server->rc.Link.pageUrl = AVcopy(pval); - pval.av_val = NULL; - } - else if (AVMATCH(&pname, &av_audioCodecs)) -@@ -287,14 +292,21 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - if (pval.av_val) - free(pval.av_val); - } -+ - if (obj.o_num > 3) - { -- if (AMFProp_GetBoolean(&obj.o_props[3])) -- server->rc.Link.lFlags |= RTMP_LF_AUTH; -- if (obj.o_num > 4) -- { -- AMFProp_GetString(&obj.o_props[4], &server->rc.Link.auth); -- } -+ int i = obj.o_num - 3; -+ server->rc.Link.extras.o_num = i; -+ server->rc.Link.extras.o_props = malloc(i * sizeof (AMFObjectProperty)); -+ memcpy(server->rc.Link.extras.o_props, obj.o_props + 3, i * sizeof (AMFObjectProperty)); -+ obj.o_num = 3; -+ } -+ -+ if (server->rc.Link.extras.o_num) -+ { -+ server->rc.Link.Extras.av_val = calloc(1024, sizeof (char)); -+ dumpAMF(&server->rc.Link.extras, server->rc.Link.Extras.av_val); -+ server->rc.Link.Extras.av_len = strlen(server->rc.Link.Extras.av_val); - } - - if (!RTMP_Connect(&server->rc, pack)) -@@ -303,6 +315,16 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - return 1; - } - server->rc.m_bSendCounter = FALSE; -+ -+ if (server->rc.Link.extras.o_props) -+ { -+ AMF_Reset(&server->rc.Link.extras); -+ } -+ } -+ else if (AVMATCH(&method, &av_NetStream_Authenticate_UsherToken)) -+ { -+ AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &server->rc.Link.usherToken); -+ RTMP_LogPrintf("%10s : %.*s\n", "usherToken", server->rc.Link.usherToken.av_len, server->rc.Link.usherToken.av_val); - } - else if (AVMATCH(&method, &av_play)) - { -@@ -323,6 +345,14 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - if (!av.av_val) - goto out; - -+ double StartFlag = 0; -+ AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4); -+ if (!(Start->p_type == AMF_INVALID)) -+ StartFlag = AMFProp_GetNumber(Start); -+ if (StartFlag == -1000 || strstr(server->rc.Link.app.av_val, "live")) -+ StartFlag = -1000; -+ RTMP_LogPrintf("%10s : %s\n", "live", (StartFlag == -1000) ? "yes" : "no"); -+ - /* check for duplicates */ - for (fl = server->f_head; fl; fl=fl->f_next) - { -@@ -372,9 +402,51 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b - for (p=file; *p; p++) - if (*p == ':') - *p = '_'; -- RTMP_LogPrintf("Playpath: %.*s\nSaving as: %s\n", -- server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val, -- file); -+ RTMP_LogPrintf("%10s : %.*s\n%10s : %s\n", "Playpath", server->rc.Link.playpath.av_len, -+ server->rc.Link.playpath.av_val, "Saving as", file); -+ -+#ifdef WIN32 -+ // Dump command to batch file -+ char *cmd = NULL, *ptr = NULL; -+ AVal swfUrl, tcUrl; -+ -+ cmd = calloc(2048, sizeof (char)); -+ ptr = cmd; -+ tcUrl = StripParams(&server->rc.Link.tcUrl); -+ swfUrl = StripParams(&server->rc.Link.swfUrl); -+ ptr += sprintf(ptr, "rtmpdump -r \"%.*s\" -a \"%.*s\" -f \"%.*s\" -W \"%.*s\" -p \"%.*s\"", -+ tcUrl.av_len, tcUrl.av_val, -+ server->rc.Link.app.av_len, server->rc.Link.app.av_val, -+ server->rc.Link.flashVer.av_len, server->rc.Link.flashVer.av_val, -+ swfUrl.av_len, swfUrl.av_val, -+ server->rc.Link.pageUrl.av_len, server->rc.Link.pageUrl.av_val); -+ -+ if (server->rc.Link.usherToken.av_val) -+ { -+ char *usherToken = strreplace(server->rc.Link.usherToken.av_val, server->rc.Link.usherToken.av_len, "\"", "\\\""); -+ usherToken = strreplace(usherToken, 0, "^", "^^"); -+ usherToken = strreplace(usherToken, 0, "|", "^|"); -+ ptr += sprintf(ptr, " --jtv \"%s\"", usherToken); -+ free(usherToken); -+ } -+ -+ if (server->rc.Link.Extras.av_len) -+ { -+ ptr += sprintf(ptr, "%.*s", server->rc.Link.Extras.av_len, server->rc.Link.Extras.av_val); -+ } -+ -+ if (StartFlag == -1000) -+ ptr += sprintf(ptr, "%s", " --live"); -+ ptr += sprintf(ptr, " -y \"%.*s\"", server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val); -+ ptr += sprintf(ptr, " -o \"%s.flv\"\n", file); -+ -+ FILE *cmdfile = fopen("Command.bat", "a"); -+ fprintf(cmdfile, "%s", cmd); -+ fclose(cmdfile); -+ -+ free(cmd); -+#endif -+ - out = fopen(file, "wb"); - free(file); - if (!out) -@@ -1196,3 +1268,146 @@ main(int argc, char **argv) - #endif - return nStatus; - } -+ -+char * -+dumpAMF(AMFObject *obj, char *ptr) -+{ -+ int i; -+ const char opt[] = "NBSO Z"; -+ -+ for (i = 0; i < obj->o_num; i++) -+ { -+ AMFObjectProperty *p = &obj->o_props[i]; -+ if (p->p_type > 5) -+ continue; -+ ptr += sprintf(ptr, " -C "); -+ if (p->p_name.av_val) -+ *ptr++ = 'N'; -+ *ptr++ = opt[p->p_type]; -+ *ptr++ = ':'; -+ if (p->p_name.av_val) -+ ptr += sprintf(ptr, "%.*s:", p->p_name.av_len, p->p_name.av_val); -+ switch (p->p_type) -+ { -+ case AMF_BOOLEAN: -+ *ptr++ = p->p_vu.p_number != 0 ? '1' : '0'; -+ break; -+ case AMF_STRING: -+ memcpy(ptr, p->p_vu.p_aval.av_val, p->p_vu.p_aval.av_len); -+ ptr += p->p_vu.p_aval.av_len; -+ break; -+ case AMF_NUMBER: -+ ptr += sprintf(ptr, "%f", p->p_vu.p_number); -+ break; -+ case AMF_OBJECT: -+ *ptr++ = '1'; -+ ptr = dumpAMF(&p->p_vu.p_object, ptr); -+ ptr += sprintf(ptr, " -C O:0"); -+ break; -+ case AMF_NULL: -+ default: -+ break; -+ } -+ } -+ return ptr; -+} -+ -+char * -+strreplace(char *srcstr, int srclen, char *orig, char *repl) -+{ -+ char *ptr = NULL, *sptr = srcstr; -+ int origlen = strlen(orig); -+ int repllen = strlen(repl); -+ if (!srclen) -+ srclen = strlen(srcstr); -+ char *srcend = srcstr + srclen; -+ int dstbuffer = srclen / origlen * repllen; -+ if (dstbuffer < srclen) -+ dstbuffer = srclen; -+ char *dststr = calloc(dstbuffer + 1, sizeof (char)); -+ char *dptr = dststr; -+ -+ if ((ptr = strstr(srcstr, orig))) -+ { -+ while (ptr < srcend && (ptr = strstr(sptr, orig))) -+ { -+ int len = ptr - sptr; -+ memcpy(dptr, sptr, len); -+ sptr += len + origlen; -+ dptr += len; -+ memcpy(dptr, repl, repllen); -+ dptr += repllen; -+ } -+ memcpy(dptr, sptr, srcend - sptr); -+ return dststr; -+ } -+ -+ memcpy(dststr, srcstr, srclen); -+ return dststr; -+} -+ -+AVal -+StripParams(AVal *src) -+{ -+ AVal str; -+ if (src->av_val) -+ { -+ str.av_val = calloc(src->av_len + 1, sizeof (char)); -+ strncpy(str.av_val, src->av_val, src->av_len); -+ str.av_len = src->av_len; -+ char *start = str.av_val; -+ char *end = start + str.av_len; -+ char *ptr = start; -+ -+ while (ptr < end) -+ { -+ if (*ptr == '?') -+ { -+ str.av_len = ptr - start; -+ break; -+ } -+ ptr++; -+ } -+ memset(start + str.av_len, 0, 1); -+ -+ char *dynamic = strstr(start, "[[DYNAMIC]]"); -+ if (dynamic) -+ { -+ dynamic -= 1; -+ memset(dynamic, 0, 1); -+ str.av_len = dynamic - start; -+ end = start + str.av_len; -+ } -+ -+ char *import = strstr(start, "[[IMPORT]]"); -+ if (import) -+ { -+ str.av_val = import + 11; -+ strcpy(start, "http://"); -+ str.av_val = strcat(start, str.av_val); -+ str.av_len = strlen(str.av_val); -+ } -+ return str; -+ } -+ str = *src; -+ return str; -+} -+ -+AVal -+AVcopy(AVal src) -+{ -+ AVal dst; -+ if (src.av_len) -+ { -+ dst.av_val = malloc(src.av_len + 1); -+ memcpy(dst.av_val, src.av_val, src.av_len); -+ dst.av_val[src.av_len] = '\0'; -+ dst.av_len = src.av_len; -+ } -+ else -+ { -+ dst.av_val = NULL; -+ dst.av_len = 0; -+ } -+ return dst; -+} diff --git a/tools/depends/target/librtmp/prefix.patch b/tools/depends/target/librtmp/prefix.patch index 198a85cf79..381797217e 100644 --- a/tools/depends/target/librtmp/prefix.patch +++ b/tools/depends/target/librtmp/prefix.patch @@ -1,7 +1,7 @@ --- librtmp/Makefile 2010-06-30 15:58:35.000000000 -0400 +++ librtmp/Makefile.2 2011-03-31 16:19:52.813884882 -0400 @@ -1,6 +1,6 @@ - VERSION=v2.3 + VERSION=v2.4 -prefix=/usr/local +prefix=$(PREFIX) |