Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git librtmp/amf.c librtmp/amf.c
- index 659421e..a25bc04 100644
- --- librtmp/amf.c
- +++ 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;
- @@ -1121,7 +1124,7 @@ AMF_GetProp(AMFObject *obj, const AVal *name, int nIndex)
- {
- if (nIndex >= 0)
- {
- - if (nIndex <= obj->o_num)
- + if (nIndex < obj->o_num)
- return &obj->o_props[nIndex];
- }
- else
- diff --git librtmp/dh.h librtmp/dh.h
- index a9f3763..90697ea 100644
- --- librtmp/dh.h
- +++ 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 librtmp/handshake.h librtmp/handshake.h
- index 98bf3c8..3bc1e5c 100644
- --- librtmp/handshake.h
- +++ librtmp/handshake.h
- @@ -962,8 +962,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 librtmp/hashswf.c librtmp/hashswf.c
- index 0320480..1f83e0a 100644
- --- librtmp/hashswf.c
- +++ 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 librtmp/log.c librtmp/log.c
- index 0012985..856e3e4 100644
- --- librtmp/log.c
- +++ 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 librtmp/rtmp.c librtmp/rtmp.c
- index 52d0254..21be6cf 100644
- --- librtmp/rtmp.c
- +++ 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 SendCustomCommand(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)
- @@ -1308,8 +1335,10 @@ ReadN(RTMP *r, char *buffer, int n)
- return 0;
- }
- }
- - if (r->m_resplen && !r->m_sb.sb_size)
- - RTMPSockBuf_Fill(&r->m_sb);
- + if (r->m_resplen && (r->m_sb.sb_size < r->m_resplen))
- + if (RTMPSockBuf_Fill(&r->m_sb) < 0)
- + if (!r->m_sb.sb_timedout)
- + RTMP_Close(r);
- avail = r->m_sb.sb_size;
- if (avail > r->m_resplen)
- avail = r->m_resplen;
- @@ -1336,10 +1365,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 (r->m_bSendCounter && r->m_nBytesIn > (r->m_nBytesInSent + r->m_nClientBW / 10))
- if (!SendBytesReceived(r))
- - return FALSE;
- + return FALSE;
- }
- /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
- #ifdef _DEBUG
- @@ -1390,6 +1418,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 +1493,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);
- @@ -2096,10 +2137,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 +2254,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 +2286,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 +2344,7 @@ AV_clear(RTMP_METHOD *vals, int num)
- free(vals);
- }
- +SAVC(onBWCheck);
- SAVC(onBWDone);
- SAVC(onFCSubscribe);
- SAVC(onFCUnsubscribe);
- @@ -2318,20 +2358,20 @@ 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_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 +2381,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 +2447,128 @@ 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"))
- + {
- + AVal av_requestAccess = AVC("requestAccess");
- + AVal av_auth = AVC("h§4jhH43d");
- + enc = pbuf;
- + enc = AMF_EncodeString(enc, pend, &av_requestAccess);
- + enc = AMF_EncodeNumber(enc, pend, 0);
- + *enc++ = AMF_NULL;
- + enc = AMF_EncodeString(enc, pend, &av_auth);
- + av_Command.av_val = pbuf;
- + av_Command.av_len = enc - pbuf;
- + SendCustomCommand(r, &av_Command, FALSE);
- +
- + AVal av_getConnectionCount = AVC("getConnectionCount");
- + enc = pbuf;
- + enc = AMF_EncodeString(enc, pend, &av_getConnectionCount);
- + enc = AMF_EncodeNumber(enc, pend, 0);
- + *enc++ = AMF_NULL;
- + av_Command.av_val = pbuf;
- + av_Command.av_len = enc - pbuf;
- + SendCustomCommand(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"))
- + {
- + AVal av_r = AVC("r");
- + enc = pbuf;
- + enc = AMF_EncodeString(enc, pend, &av_r);
- + enc = AMF_EncodeNumber(enc, pend, 0);
- + *enc++ = AMF_NULL;
- + av_Command.av_val = pbuf;
- + av_Command.av_len = enc - pbuf;
- + SendCustomCommand(r, &av_Command, FALSE);
- +
- + SendGetStreamLength(r);
- + }
- + else if (strstr(host, "chaturbate.com") || strstr(pageUrl, "chaturbate.com"))
- + {
- + AVal av_ModelName;
- + AVal av_CheckPublicStatus = AVC("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, 0);
- + *enc++ = AMF_NULL;
- + enc = AMF_EncodeString(enc, pend, &av_ModelName);
- + av_Command.av_val = pbuf;
- + av_Command.av_len = enc - pbuf;
- +
- + SendCustomCommand(r, &av_Command, FALSE);
- + }
- + }
- + /* Weeb.tv specific authentication */
- + else if (r->Link.WeebToken.av_len)
- + {
- + AVal av_Token, av_Username, av_Password;
- + AVal av_determineAccess = AVC("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, 0);
- + *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);
- + SendCustomCommand(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 +2591,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 +2607,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);
- }
- @@ -2563,6 +2713,77 @@ 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, AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1)));
- + *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);
- + SendCustomCommand(r, &av_Response, FALSE);
- + }
- + else if (AVMATCH(&method, &av_sendStatus))
- + {
- + if (r->Link.WeebToken.av_len)
- + {
- + AVal av_Code = AVC("code");
- + 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);
- + param_count = 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;
- + char *str = malloc(sizeof ("mp4:") + strlen(params[1]));
- + str = strcpy(str, "mp4:");
- + Playpath.av_val = strcat(str, params[1]);
- + Playpath.av_len = strlen(Playpath.av_val);
- + r->Link.playpath = Playpath;
- + RTMP_SendCreateStream(r);
- + }
- + }
- else
- {
- @@ -2748,7 +2969,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 +3077,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);
- }
- @@ -3709,12 +3930,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 +3969,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 < 3584)
- + 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--;
- @@ -4458,3 +4686,90 @@ RTMP_Write(RTMP *r, const char *buf, int size)
- }
- return size+s2;
- }
- +
- +static int
- +SendCustomCommand(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 SendCustomCommand(r, &av_Command, TRUE);
- +}
- diff --git librtmp/rtmp.h librtmp/rtmp.h
- index 6b2ae5b..96507df 100644
- --- librtmp/rtmp.h
- +++ 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,14 @@ extern "C"
- int lFlags;
- int swfAge;
- + int swfSize;
- int protocol;
- + int ConnectPacket;
- + int CombineConnectPacket;
- int timeout; /* connection timeout in seconds */
- + AVal Extras;
- + AVal HandshakeResponse;
- unsigned short socksport;
- unsigned short port;
- @@ -299,6 +306,7 @@ extern "C"
- AVal *flashVer,
- AVal *subscribepath,
- AVal *usherToken,
- + AVal *WeebToken,
- int dStart,
- int dStop, int bLiveStream, long int timeout);
- diff --git librtmp/rtmp_sys.h librtmp/rtmp_sys.h
- index c3fd4a6..665dcd1 100644
- --- librtmp/rtmp_sys.h
- +++ librtmp/rtmp_sys.h
- @@ -71,7 +71,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)
- diff --git rtmpdump.c rtmpdump.c
- index 34bfdba..02c9781 100644
- --- rtmpdump.c
- +++ rtmpdump.c
- @@ -697,6 +697,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",
- @@ -743,7 +745,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;
- @@ -846,12 +849,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,
- - "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:",
- + "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)
- @@ -1061,6 +1065,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]);
- @@ -1152,14 +1159,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;
- @@ -1178,7 +1185,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 && !(protocol & RTMP_FEATURE_HTTP))
- diff --git rtmpgw.c rtmpgw.c
- index 0cf56bb..cd4396d 100644
- --- rtmpgw.c
- +++ 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 rtmpsrv.c rtmpsrv.c
- index b662d54..0b001be 100644
- --- rtmpsrv.c
- +++ rtmpsrv.c
- @@ -96,9 +96,19 @@ 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, double txn);
- +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 +177,8 @@ SAVC(level);
- SAVC(code);
- SAVC(description);
- SAVC(secureToken);
- +SAVC(_checkbw);
- +SAVC(_onbwdone);
- static int
- SendConnectResult(RTMP *r, double txn)
- @@ -271,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; */
- @@ -303,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; */
- @@ -331,6 +343,33 @@ SendPlayStop(RTMP *r)
- return RTMP_SendPacket(r, &packet, FALSE);
- }
- +int
- +SendCheckBWResponse(RTMP *r, double txn)
- +{
- + 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;
- + enc = AMF_EncodeString(enc, pend, &av__onbwdone);
- + enc = AMF_EncodeNumber(enc, pend, txn);
- + *enc++ = AMF_NULL;
- + enc = AMF_EncodeNumber(enc, pend, 10240);
- + enc = AMF_EncodeNumber(enc, pend, 10240);
- +
- + packet.m_nBodySize = enc - packet.m_body;
- +
- + return RTMP_SendPacket(r, &packet, FALSE);
- +}
- +
- static void
- spawn_dumper(int argc, AVal *av, char *cmd)
- {
- @@ -585,10 +624,18 @@ 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, txn);
- + }
- else if (AVMATCH(&method, &av_play))
- {
- char *file, *p, *q, *cmd, *ptr;
- @@ -602,6 +649,19 @@ 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));
- */
- +#ifdef VLC
- + double StartFlag = -1000;
- +#else
- + double StartFlag = 0;
- +#endif
- + AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4);
- + if (!(Start->p_type == AMF_INVALID))
- + StartFlag = AMFProp_GetNumber(Start);
- + if (StartFlag < 0)
- + {
- + server->arglen += 7;
- + server->argc += 1;
- + }
- if (r->Link.tcUrl.av_len)
- {
- len = server->arglen + r->Link.playpath.av_len + 4 +
- @@ -619,6 +679,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;
- @@ -643,6 +704,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;
- }
- @@ -665,10 +727,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 < 0)
- + {
- + 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;
- @@ -676,7 +745,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)
- @@ -728,7 +803,14 @@ 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;
- +#ifdef VLC
- + if (file_exists("C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe"))
- + ptr += sprintf(ptr, " | %s -", "\"C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe\"");
- + else
- + ptr += sprintf(ptr, " | %s -", "\"C:\\Program Files\\VideoLAN\\VLC\\vlc.exe\"");
- +#else
- ptr += sprintf(ptr, " -o %s", file);
- +#endif
- now = RTMP_GetTime();
- if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename))
- {
- @@ -742,7 +824,23 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
- server->filetime = now;
- free(server->filename.av_val);
- server->filename = argv[argc++];
- +#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);
- @@ -1142,6 +1240,99 @@ main(int argc, char **argv)
- return nStatus;
- }
- +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 1;
- + }
- + return 0;
- +}
- +
- void
- AVreplace(AVal *src, const AVal *orig, const AVal *repl)
- {
- diff --git rtmpsuck.c rtmpsuck.c
- index e886179..f8cfb7c 100644
- --- rtmpsuck.c
- +++ 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 StripParams(AVal *src);
- +AVal AVcopy(AVal src);
- // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete'
- int
- @@ -198,26 +201,29 @@ 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 +231,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 +273,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 +293,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 +316,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 +346,12 @@ 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);
- + RTMP_LogPrintf("%10s : %s\n", "live", (StartFlag < 0) ? "yes" : "no");
- +
- /* check for duplicates */
- for (fl = server->f_head; fl; fl=fl->f_next)
- {
- @@ -372,9 +401,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 < 0)
- + 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 +1267,145 @@ 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);
- + memcpy(dst.av_val, src.av_val, src.av_len);
- + dst.av_len = src.av_len;
- + }
- + else
- + {
- + dst.av_val = NULL;
- + dst.av_len = 0;
- + }
- + return dst;
- +}
Add Comment
Please, Sign In to add comment