aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorRainer Hochecker <fernetmenta@online.de>2015-01-30 15:25:44 +0100
committerRainer Hochecker <fernetmenta@online.de>2015-01-30 15:25:44 +0100
commit2be805c56776716d2fc269b5376ebf3f495e7a98 (patch)
tree2845df6368c1db8e0f4c376b31f18795f28ec984 /tools
parent5ff422b4aa2cb8fbc9ca8df72a1f3c70786f2eb2 (diff)
parent679d444a4e044d63ea337455c295fbd38c2b1b86 (diff)
Merge pull request #6283 from FernetMenta/rtmp
bump librtmp
Diffstat (limited to 'tools')
-rw-r--r--tools/depends/target/librtmp/Makefile7
-rw-r--r--tools/depends/target/librtmp/librtmp-60-second-fix.patch1913
-rw-r--r--tools/depends/target/librtmp/prefix.patch2
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, '/', &params);
-+ 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, ';', &params);
-+ 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, ':', &params);
-+ 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, ',', &params);
-+ 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)