Guest User

Untitled

a guest
Mar 3rd, 2012
812
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 55.95 KB | None | 0 0
  1. diff --git librtmp/amf.c librtmp/amf.c
  2. index 659421e..a25bc04 100644
  3. --- librtmp/amf.c
  4. +++ librtmp/amf.c
  5. @@ -610,6 +610,9 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
  6.        return -1;
  7.      }
  8.  
  9. +  if (*pBuffer == AMF_NULL)
  10. +    bDecodeName = 0;
  11. +
  12.    if (bDecodeName && nSize < 4)
  13.      {              /* at least name (length + at least 1 byte) and 1 byte of data */
  14.        RTMP_Log(RTMP_LOGDEBUG,
  15. @@ -801,8 +804,8 @@ AMFProp_Dump(AMFObjectProperty *prop)
  16.      }
  17.    else
  18.      {
  19. -      name.av_val = "no-name.";
  20. -      name.av_len = sizeof("no-name.") - 1;
  21. +      name.av_val = "no-name";
  22. +      name.av_len = sizeof("no-name") - 1;
  23.      }
  24.    if (name.av_len > 18)
  25.      name.av_len = 18;
  26. @@ -1121,7 +1124,7 @@ AMF_GetProp(AMFObject *obj, const AVal *name, int nIndex)
  27.  {
  28.    if (nIndex >= 0)
  29.      {
  30. -      if (nIndex <= obj->o_num)
  31. +      if (nIndex < obj->o_num)
  32.     return &obj->o_props[nIndex];
  33.      }
  34.    else
  35. diff --git librtmp/dh.h librtmp/dh.h
  36. index a9f3763..90697ea 100644
  37. --- librtmp/dh.h
  38. +++ librtmp/dh.h
  39. @@ -61,7 +61,7 @@ static int MDH_generate_key(MDH *dh)
  40.    MP_set(&dh->ctx.P, dh->p);
  41.    MP_set(&dh->ctx.G, dh->g);
  42.    dh->ctx.len = 128;
  43. -  dhm_make_public(&dh->ctx, 1024, out, 1, havege_rand, &RTMP_TLS_ctx->hs);
  44. +  dhm_make_public(&dh->ctx, 1024, out, 1, havege_random, &RTMP_TLS_ctx->hs);
  45.    MP_new(dh->pub_key);
  46.    MP_new(dh->priv_key);
  47.    MP_set(dh->pub_key, &dh->ctx.GX);
  48. diff --git librtmp/handshake.h librtmp/handshake.h
  49. index 98bf3c8..3bc1e5c 100644
  50. --- librtmp/handshake.h
  51. +++ librtmp/handshake.h
  52. @@ -962,8 +962,18 @@ HandShake(RTMP * r, int FP9HandShake)
  53.      __FUNCTION__);
  54.    RTMP_LogHex(RTMP_LOGDEBUG, reply, RTMP_SIG_SIZE);
  55.  #endif
  56. -  if (!WriteN(r, (char *)reply, RTMP_SIG_SIZE))
  57. -    return FALSE;
  58. +  if (r->Link.CombineConnectPacket)
  59. +    {
  60. +      char *HandshakeResponse = malloc(RTMP_SIG_SIZE);
  61. +      memcpy(HandshakeResponse, (char *) reply, RTMP_SIG_SIZE);
  62. +      r->Link.HandshakeResponse.av_val = HandshakeResponse;
  63. +      r->Link.HandshakeResponse.av_len = RTMP_SIG_SIZE;
  64. +    }
  65. +  else
  66. +    {
  67. +      if (!WriteN(r, (char *) reply, RTMP_SIG_SIZE))
  68. +        return FALSE;
  69. +    }
  70.  
  71.    /* 2nd part of handshake */
  72.    if (ReadN(r, (char *)serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
  73. diff --git librtmp/hashswf.c librtmp/hashswf.c
  74. index 0320480..1f83e0a 100644
  75. --- librtmp/hashswf.c
  76. +++ librtmp/hashswf.c
  77. @@ -70,7 +70,7 @@ extern TLS_CTX RTMP_TLS_ctx;
  78.  
  79.  #endif /* CRYPTO */
  80.  
  81. -#define    AGENT   "Mozilla/5.0"
  82. +#define    AGENT   "Mozilla/5.0 (Windows NT 5.1; rv:8.0) Gecko/20100101 Firefox/8.0"
  83.  
  84.  HTTPResult
  85.  HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
  86. @@ -528,7 +528,7 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash,
  87.  
  88.       if (strncmp(buf, "url: ", 5))
  89.         continue;
  90. -     if (strncmp(buf + 5, url, hlen))
  91. +     if (strncmp(buf + 5, url, strlen(buf + 5) - 1))
  92.         continue;
  93.       r1 = strrchr(buf, '/');
  94.       i = strlen(r1);
  95. diff --git librtmp/log.c librtmp/log.c
  96. index 0012985..856e3e4 100644
  97. --- librtmp/log.c
  98. +++ librtmp/log.c
  99. @@ -52,8 +52,8 @@ static void rtmp_log_default(int level, const char *format, va_list vl)
  100.     vsnprintf(str, MAX_PRINT_LEN-1, format, vl);
  101.  
  102.     /* Filter out 'no-name' */
  103. -   if ( RTMP_debuglevel<RTMP_LOGALL && strstr(str, "no-name" ) != NULL )
  104. -       return;
  105. +   if (RTMP_debuglevel < RTMP_LOGDEBUG && strstr(str, "no-name") != NULL)
  106. +     return;
  107.  
  108.     if ( !fmsg ) fmsg = stderr;
  109.  
  110. diff --git librtmp/rtmp.c librtmp/rtmp.c
  111. index 52d0254..21be6cf 100644
  112. --- librtmp/rtmp.c
  113. +++ librtmp/rtmp.c
  114. @@ -27,6 +27,7 @@
  115.  #include <stdlib.h>
  116.  #include <string.h>
  117.  #include <assert.h>
  118. +#include <math.h>
  119.  
  120.  #include "rtmp_sys.h"
  121.  #include "log.h"
  122. @@ -45,6 +46,7 @@ TLS_CTX RTMP_TLS_ctx;
  123.  
  124.  #define RTMP_SIG_SIZE 1536
  125.  #define RTMP_LARGE_HEADER_SIZE 12
  126. +#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
  127.  
  128.  static const int packetSize[] = { 12, 8, 4, 1 };
  129.  
  130. @@ -97,6 +99,9 @@ static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
  131.  static int SendPlay(RTMP *r);
  132.  static int SendBytesReceived(RTMP *r);
  133.  static int SendUsherToken(RTMP *r, AVal *usherToken);
  134. +static int SendCustomCommand(RTMP *r, AVal *Command, int queue);
  135. +static int SendGetStreamLength(RTMP *r);
  136. +static int strsplit(char *src, int srclen, char delim, char ***params);
  137.  
  138.  #if 0              /* unused */
  139.  static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
  140. @@ -259,6 +264,8 @@ RTMP_Init(RTMP *r)
  141.    r->m_fVideoCodecs = 252.0;
  142.    r->Link.timeout = 30;
  143.    r->Link.swfAge = 30;
  144. +  r->Link.CombineConnectPacket = TRUE;
  145. +  r->Link.ConnectPacket = FALSE;
  146.  }
  147.  
  148.  void
  149. @@ -337,6 +344,7 @@ RTMP_SetupStream(RTMP *r,
  150.          AVal *flashVer,
  151.          AVal *subscribepath,
  152.          AVal *usherToken,
  153. +        AVal *WeebToken,
  154.          int dStart,
  155.          int dStop, int bLiveStream, long int timeout)
  156.  {
  157. @@ -359,6 +367,8 @@ RTMP_SetupStream(RTMP *r,
  158.      RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
  159.    if (usherToken && usherToken->av_val)
  160.      RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
  161. +  if (WeebToken && WeebToken->av_val)
  162. +    RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", WeebToken->av_val);
  163.    if (flashVer && flashVer->av_val)
  164.      RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
  165.    if (dStart > 0)
  166. @@ -426,6 +436,8 @@ RTMP_SetupStream(RTMP *r,
  167.      r->Link.subscribepath = *subscribepath;
  168.    if (usherToken && usherToken->av_len)
  169.      r->Link.usherToken = *usherToken;
  170. +  if (WeebToken && WeebToken->av_len)
  171. +    r->Link.WeebToken = *WeebToken;
  172.    r->Link.seekTime = dStart;
  173.    r->Link.stopTime = dStop;
  174.    if (bLiveStream)
  175. @@ -483,14 +495,22 @@ static struct urlopt {
  176.     "Stream is live, no seeking possible" },
  177.    { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
  178.     "Stream to subscribe to" },
  179. -  { AVC("jtv"), OFF(Link.usherToken),          OPT_STR, 0,
  180. -   "Justin.tv authentication token" },
  181. -  { AVC("token"),     OFF(Link.token),        OPT_STR, 0,
  182. +  { AVC("jtv"),       OFF(Link.usherToken),    OPT_STR, 0,
  183. +        "Justin.tv authentication token"},
  184. +  { AVC("weeb"),      OFF(Link.WeebToken),     OPT_STR, 0,
  185. +        "Weeb.tv authentication token"},
  186. +  { AVC("token"),     OFF(Link.token),         OPT_STR, 0,
  187.     "Key for SecureToken response" },
  188.    { AVC("swfVfy"),    OFF(Link.lFlags),        OPT_BOOL, RTMP_LF_SWFV,
  189.     "Perform SWF Verification" },
  190.    { AVC("swfAge"),    OFF(Link.swfAge),        OPT_INT, 0,
  191.     "Number of days to use cached SWF hash" },
  192. +#ifdef CRYPTO
  193. +  { AVC("swfsize"),   OFF(Link.swfSize),       OPT_INT, 0,
  194. +        "Size of the decompressed SWF file"},
  195. +  { AVC("swfhash"),   OFF(Link.swfHash),       OPT_STR, 0,
  196. +        "SHA256 hash of the decompressed SWF file"},
  197. +#endif
  198.    { AVC("start"),     OFF(Link.seekTime),      OPT_INT, 0,
  199.     "Stream start position in milliseconds" },
  200.    { AVC("stop"),      OFF(Link.stopTime),      OPT_INT, 0,
  201. @@ -751,9 +771,16 @@ int RTMP_SetupURL(RTMP *r, char *url)
  202.      }
  203.  
  204.  #ifdef CRYPTO
  205. -  if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
  206. -    RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
  207. -     (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
  208. +  RTMP_Log(RTMP_LOGDEBUG, "Khalsa: %d %d %s\n", r->Link.swfSize, r->Link.swfHash.av_len, r->Link.swfHash.av_val);
  209. +  if (r->Link.swfSize && r->Link.swfHash.av_len)
  210. +    {
  211. +      int i, j = 0;
  212. +      for (i = 0; i < r->Link.swfHash.av_len; i += 2)
  213. +        r->Link.SWFHash[j++] = (HEX2BIN(r->Link.swfHash.av_val[i]) << 4) | HEX2BIN(r->Link.swfHash.av_val[i + 1]);
  214. +      r->Link.SWFSize = (uint32_t) r->Link.swfSize;
  215. +    }
  216. +  else if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
  217. +    RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize, (unsigned char *) r->Link.SWFHash, r->Link.swfAge);
  218.  #endif
  219.  
  220.    if (r->Link.port == 0)
  221. @@ -1308,8 +1335,10 @@ ReadN(RTMP *r, char *buffer, int n)
  222.           return 0;
  223.         }
  224.         }
  225. -     if (r->m_resplen && !r->m_sb.sb_size)
  226. -       RTMPSockBuf_Fill(&r->m_sb);
  227. +          if (r->m_resplen && (r->m_sb.sb_size < r->m_resplen))
  228. +            if (RTMPSockBuf_Fill(&r->m_sb) < 0)
  229. +              if (!r->m_sb.sb_timedout)
  230. +                RTMP_Close(r);
  231.            avail = r->m_sb.sb_size;
  232.       if (avail > r->m_resplen)
  233.         avail = r->m_resplen;
  234. @@ -1336,10 +1365,9 @@ ReadN(RTMP *r, char *buffer, int n)
  235.       r->m_sb.sb_size -= nRead;
  236.       nBytes = nRead;
  237.       r->m_nBytesIn += nRead;
  238. -     if (r->m_bSendCounter
  239. -         && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
  240. +     if (r->m_bSendCounter && r->m_nBytesIn > (r->m_nBytesInSent + r->m_nClientBW / 10))
  241.         if (!SendBytesReceived(r))
  242. -           return FALSE;
  243. +         return FALSE;
  244.     }
  245.        /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
  246.  #ifdef _DEBUG
  247. @@ -1390,6 +1418,16 @@ WriteN(RTMP *r, const char *buffer, int n)
  248.      }
  249.  #endif
  250.  
  251. +  if (r->Link.ConnectPacket)
  252. +    {
  253. +      char *ConnectPacket = malloc(r->Link.HandshakeResponse.av_len + n);
  254. +      memcpy(ConnectPacket, r->Link.HandshakeResponse.av_val, r->Link.HandshakeResponse.av_len);
  255. +      memcpy(ConnectPacket + r->Link.HandshakeResponse.av_len, ptr, n);
  256. +      ptr = ConnectPacket;
  257. +      n += r->Link.HandshakeResponse.av_len;
  258. +      r->Link.ConnectPacket = FALSE;
  259. +    }
  260. +
  261.    while (n > 0)
  262.      {
  263.        int nBytes;
  264. @@ -1455,6 +1493,9 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp)
  265.    char pbuf[4096], *pend = pbuf + sizeof(pbuf);
  266.    char *enc;
  267.  
  268. +  if (r->Link.CombineConnectPacket)
  269. +    r->Link.ConnectPacket = TRUE;
  270. +
  271.    if (cp)
  272.      return RTMP_SendPacket(r, cp, TRUE);
  273.  
  274. @@ -2096,10 +2137,8 @@ SendPlay(RTMP *r)
  275.      enc = AMF_EncodeNumber(enc, pend, -1000.0);
  276.    else
  277.      {
  278. -      if (r->Link.seekTime > 0.0)
  279. -   enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime);    /* resume from here */
  280. -      else
  281. -   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 */
  282. +      if (r->Link.seekTime > 0.0 || r->Link.stopTime)
  283. +        enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
  284.      }
  285.    if (!enc)
  286.      return FALSE;
  287. @@ -2215,7 +2254,7 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
  288.    int nSize;
  289.    char *buf;
  290.  
  291. -  RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
  292. +  RTMP_Log(RTMP_LOGDEBUG, "sending ctrl, type: 0x%04x", (unsigned short)nType);
  293.  
  294.    packet.m_nChannel = 0x02;    /* control channel (ping) */
  295.    packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
  296. @@ -2247,8 +2286,8 @@ RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
  297.      }
  298.    else if (nType == 0x1A)
  299.      {
  300. -     *buf = nObject & 0xff;
  301. -   }
  302. +      *buf = nObject & 0xff;
  303. +    }
  304.    else
  305.      {
  306.        if (nSize > 2)
  307. @@ -2305,6 +2344,7 @@ AV_clear(RTMP_METHOD *vals, int num)
  308.    free(vals);
  309.  }
  310.  
  311. +SAVC(onBWCheck);
  312.  SAVC(onBWDone);
  313.  SAVC(onFCSubscribe);
  314.  SAVC(onFCUnsubscribe);
  315. @@ -2318,20 +2358,20 @@ SAVC(onStatus);
  316.  SAVC(playlist_ready);
  317.  static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
  318.  static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
  319. -static const AVal av_NetStream_Play_StreamNotFound =
  320. -AVC("NetStream.Play.StreamNotFound");
  321. -static const AVal av_NetConnection_Connect_InvalidApp =
  322. -AVC("NetConnection.Connect.InvalidApp");
  323. +static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound");
  324. +static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp");
  325.  static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
  326.  static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
  327.  static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
  328.  static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
  329.  static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
  330. -static const AVal av_NetStream_Play_PublishNotify =
  331. -AVC("NetStream.Play.PublishNotify");
  332. -static const AVal av_NetStream_Play_UnpublishNotify =
  333. -AVC("NetStream.Play.UnpublishNotify");
  334. +static const AVal av_NetStream_Play_PublishNotify = AVC("NetStream.Play.PublishNotify");
  335. +static const AVal av_NetStream_Play_UnpublishNotify = AVC("NetStream.Play.UnpublishNotify");
  336.  static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
  337. +static const AVal av_verifyClient = AVC("verifyClient");
  338. +static const AVal av_sendStatus = AVC("sendStatus");
  339. +static const AVal av_getStreamLength = AVC("getStreamLength");
  340. +static const AVal av_ReceiveCheckPublicStatus = AVC("ReceiveCheckPublicStatus");
  341.  
  342.  /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
  343.  static int
  344. @@ -2341,6 +2381,11 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
  345.    AVal method;
  346.    double txn;
  347.    int ret = 0, nRes;
  348. +  char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc, **params = NULL;
  349. +  char *host = r->Link.hostname.av_len ? r->Link.hostname.av_val : "";
  350. +  char *pageUrl = r->Link.pageUrl.av_len ? r->Link.pageUrl.av_val : "";
  351. +  int param_count;
  352. +  AVal av_Command, av_Response;
  353.    if (body[0] != 0x02)     /* make sure it is a string method name we start with */
  354.      {
  355.        RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
  356. @@ -2402,23 +2447,128 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
  357.           RTMP_SendServerBW(r);
  358.           RTMP_SendCtrl(r, 3, 0, 300);
  359.         }
  360. -     RTMP_SendCreateStream(r);
  361. -
  362. -     if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
  363. -       {
  364. -         /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
  365. -         if (r->Link.usherToken.av_len)
  366. -           SendUsherToken(r, &r->Link.usherToken);
  367. -         /* Send the FCSubscribe if live stream or if subscribepath is set */
  368. -         if (r->Link.subscribepath.av_len)
  369. -           SendFCSubscribe(r, &r->Link.subscribepath);
  370. -         else if (r->Link.lFlags & RTMP_LF_LIVE)
  371. -           SendFCSubscribe(r, &r->Link.playpath);
  372. -       }
  373. -   }
  374. +          if (strstr(host, "tv-stream.to") || strstr(pageUrl, "tv-stream.to"))
  375. +            {
  376. +              AVal av_requestAccess = AVC("requestAccess");
  377. +              AVal av_auth = AVC("h§4jhH43d");
  378. +              enc = pbuf;
  379. +              enc = AMF_EncodeString(enc, pend, &av_requestAccess);
  380. +              enc = AMF_EncodeNumber(enc, pend, 0);
  381. +              *enc++ = AMF_NULL;
  382. +              enc = AMF_EncodeString(enc, pend, &av_auth);
  383. +              av_Command.av_val = pbuf;
  384. +              av_Command.av_len = enc - pbuf;
  385. +              SendCustomCommand(r, &av_Command, FALSE);
  386. +
  387. +              AVal av_getConnectionCount = AVC("getConnectionCount");
  388. +              enc = pbuf;
  389. +              enc = AMF_EncodeString(enc, pend, &av_getConnectionCount);
  390. +              enc = AMF_EncodeNumber(enc, pend, 0);
  391. +              *enc++ = AMF_NULL;
  392. +              av_Command.av_val = pbuf;
  393. +              av_Command.av_len = enc - pbuf;
  394. +              SendCustomCommand(r, &av_Command, FALSE);
  395. +
  396. +              SendGetStreamLength(r);
  397. +            }
  398. +          else if (strstr(host, "jampo.com.ua") || strstr(pageUrl, "jampo.com.ua"))
  399. +            {
  400. +              SendGetStreamLength(r);
  401. +            }
  402. +          else if (strstr(host, "streamscene.cc") || strstr(pageUrl, "streamscene.cc")
  403. +                   || strstr(host, "tsboard.tv") || strstr(pageUrl, "teamstream.in"))
  404. +            {
  405. +              AVal av_r = AVC("r");
  406. +              enc = pbuf;
  407. +              enc = AMF_EncodeString(enc, pend, &av_r);
  408. +              enc = AMF_EncodeNumber(enc, pend, 0);
  409. +              *enc++ = AMF_NULL;
  410. +              av_Command.av_val = pbuf;
  411. +              av_Command.av_len = enc - pbuf;
  412. +              SendCustomCommand(r, &av_Command, FALSE);
  413. +
  414. +              SendGetStreamLength(r);
  415. +            }
  416. +          else if (strstr(host, "chaturbate.com") || strstr(pageUrl, "chaturbate.com"))
  417. +            {
  418. +              AVal av_ModelName;
  419. +              AVal av_CheckPublicStatus = AVC("CheckPublicStatus");
  420. +
  421. +              if (strlen(pageUrl) > 7)
  422. +                {
  423. +                  strsplit(pageUrl + 7, FALSE, '/', &params);
  424. +                  av_ModelName.av_val = params[1];
  425. +                  av_ModelName.av_len = strlen(params[1]);
  426. +
  427. +                  enc = pbuf;
  428. +                  enc = AMF_EncodeString(enc, pend, &av_CheckPublicStatus);
  429. +                  enc = AMF_EncodeNumber(enc, pend, 0);
  430. +                  *enc++ = AMF_NULL;
  431. +                  enc = AMF_EncodeString(enc, pend, &av_ModelName);
  432. +                  av_Command.av_val = pbuf;
  433. +                  av_Command.av_len = enc - pbuf;
  434. +
  435. +                  SendCustomCommand(r, &av_Command, FALSE);
  436. +                }
  437. +            }
  438. +          /* Weeb.tv specific authentication */
  439. +          else if (r->Link.WeebToken.av_len)
  440. +            {
  441. +              AVal av_Token, av_Username, av_Password;
  442. +              AVal av_determineAccess = AVC("determineAccess");
  443. +
  444. +              param_count = strsplit(r->Link.WeebToken.av_val, FALSE, ';', &params);
  445. +              if (param_count >= 1)
  446. +                {
  447. +                  av_Token.av_val = params[0];
  448. +                  av_Token.av_len = strlen(params[0]);
  449. +                }
  450. +              if (param_count >= 2)
  451. +                {
  452. +                  av_Username.av_val = params[1];
  453. +                  av_Username.av_len = strlen(params[1]);
  454. +                }
  455. +              if (param_count >= 3)
  456. +                {
  457. +                  av_Password.av_val = params[2];
  458. +                  av_Password.av_len = strlen(params[2]);
  459. +                }
  460. +
  461. +              enc = pbuf;
  462. +              enc = AMF_EncodeString(enc, pend, &av_determineAccess);
  463. +              enc = AMF_EncodeNumber(enc, pend, 0);
  464. +              *enc++ = AMF_NULL;
  465. +              enc = AMF_EncodeString(enc, pend, &av_Token);
  466. +              enc = AMF_EncodeString(enc, pend, &av_Username);
  467. +              enc = AMF_EncodeString(enc, pend, &av_Password);
  468. +              av_Command.av_val = pbuf;
  469. +              av_Command.av_len = enc - pbuf;
  470. +
  471. +              RTMP_Log(RTMP_LOGDEBUG, "WeebToken: %s", r->Link.WeebToken.av_val);
  472. +              SendCustomCommand(r, &av_Command, FALSE);
  473. +            }
  474. +          else
  475. +            RTMP_SendCreateStream(r);
  476. +        }
  477. +      else if (AVMATCH(&methodInvoked, &av_getStreamLength))
  478. +        {
  479. +          RTMP_SendCreateStream(r);
  480. +        }
  481.        else if (AVMATCH(&methodInvoked, &av_createStream))
  482. -   {
  483. -     r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
  484. +        {
  485. +          r->m_stream_id = (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
  486. +
  487. +          if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
  488. +            {
  489. +              /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
  490. +              if (r->Link.usherToken.av_len)
  491. +                SendUsherToken(r, &r->Link.usherToken);
  492. +              /* Send the FCSubscribe if live stream or if subscribepath is set */
  493. +              if (r->Link.subscribepath.av_len)
  494. +                SendFCSubscribe(r, &r->Link.subscribepath);
  495. +              else if ((r->Link.lFlags & RTMP_LF_LIVE) && (!r->Link.WeebToken.av_len))
  496. +                SendFCSubscribe(r, &r->Link.playpath);
  497. +            }
  498.  
  499.       if (r->Link.protocol & RTMP_FEATURE_WRITE)
  500.         {
  501. @@ -2441,7 +2591,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
  502.      }
  503.    else if (AVMATCH(&method, &av_onBWDone))
  504.      {
  505. -     if (!r->m_nBWCheckCounter)
  506. +      if (!r->m_nBWCheckCounter)
  507.          SendCheckBW(r);
  508.      }
  509.    else if (AVMATCH(&method, &av_onFCSubscribe))
  510. @@ -2457,7 +2607,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
  511.      {
  512.        SendPong(r, txn);
  513.      }
  514. -  else if (AVMATCH(&method, &av__onbwcheck))
  515. +  else if (AVMATCH(&method, &av__onbwcheck) || AVMATCH(&method, &av_onBWCheck))
  516.      {
  517.        SendCheckBWResult(r, txn);
  518.      }
  519. @@ -2563,6 +2713,77 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
  520.         }
  521.          }
  522.      }
  523. +  else if (AVMATCH(&method, &av_verifyClient))
  524. +    {
  525. +      double VerificationNumber = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
  526. +      RTMP_Log(RTMP_LOGDEBUG, "VerificationNumber: %.2f", VerificationNumber);
  527. +
  528. +      enc = pbuf;
  529. +      enc = AMF_EncodeString(enc, pend, &av__result);
  530. +      enc = AMF_EncodeNumber(enc, pend, AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1)));
  531. +      *enc++ = AMF_NULL;
  532. +      enc = AMF_EncodeNumber(enc, pend, exp(atan(sqrt(VerificationNumber))) + 1);
  533. +      av_Response.av_val = pbuf;
  534. +      av_Response.av_len = enc - pbuf;
  535. +
  536. +      AMF_Decode(&obj, av_Response.av_val, av_Response.av_len, FALSE);
  537. +      AMF_Dump(&obj);
  538. +      SendCustomCommand(r, &av_Response, FALSE);
  539. +    }
  540. +  else if (AVMATCH(&method, &av_sendStatus))
  541. +    {
  542. +      if (r->Link.WeebToken.av_len)
  543. +        {
  544. +          AVal av_Code = AVC("code");
  545. +          AVal av_Authorized = AVC("User.hasAccess");
  546. +          AVal av_TransferLimit = AVC("User.noPremium.limited");
  547. +          AVal av_UserLimit = AVC("User.noPremium.tooManyUsers");
  548. +          AVal av_TimeLeft = AVC("timeLeft");
  549. +          AVal av_Status, av_ReconnectionTime;
  550. +
  551. +          AMFObject Status;
  552. +          AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &Status);
  553. +          AMFProp_GetString(AMF_GetProp(&Status, &av_Code, -1), &av_Status);
  554. +          RTMP_Log(RTMP_LOGINFO, "%.*s", av_Status.av_len, av_Status.av_val);
  555. +          if (AVMATCH(&av_Status, &av_Authorized))
  556. +            {
  557. +              RTMP_Log(RTMP_LOGINFO, "Weeb.tv authentication successful");
  558. +              RTMP_SendCreateStream(r);
  559. +            }
  560. +          else if (AVMATCH(&av_Status, &av_UserLimit))
  561. +            {
  562. +              RTMP_Log(RTMP_LOGINFO, "No free slots available");
  563. +              RTMP_Close(r);
  564. +            }
  565. +          else if (AVMATCH(&av_Status, &av_TransferLimit))
  566. +            {
  567. +              AMFProp_GetString(AMF_GetProp(&Status, &av_TimeLeft, -1), &av_ReconnectionTime);
  568. +              RTMP_Log(RTMP_LOGINFO, "Viewing limit exceeded. try again in %.*s minutes.", av_ReconnectionTime.av_len, av_ReconnectionTime.av_val);
  569. +              RTMP_Close(r);
  570. +            }
  571. +        }
  572. +    }
  573. +  else if (AVMATCH(&method, &av_ReceiveCheckPublicStatus))
  574. +    {
  575. +      AVal Status;
  576. +      AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &Status);
  577. +      param_count = strsplit(Status.av_val, Status.av_len, ',', &params);
  578. +      if (strcmp(params[0], "0") == 0)
  579. +        {
  580. +          RTMP_Log(RTMP_LOGINFO, "Model status is %s", params[1]);
  581. +          RTMP_Close(r);
  582. +        }
  583. +      else
  584. +        {
  585. +          AVal Playpath;
  586. +          char *str = malloc(sizeof ("mp4:") + strlen(params[1]));
  587. +          str = strcpy(str, "mp4:");
  588. +          Playpath.av_val = strcat(str, params[1]);
  589. +          Playpath.av_len = strlen(Playpath.av_val);
  590. +          r->Link.playpath = Playpath;
  591. +          RTMP_SendCreateStream(r);
  592. +        }
  593. +    }
  594.    else
  595.      {
  596.  
  597. @@ -2748,7 +2969,7 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet)
  598.    unsigned int tmp;
  599.    if (packet->m_body && packet->m_nBodySize >= 2)
  600.      nType = AMF_DecodeInt16(packet->m_body);
  601. -  RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
  602. +  RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl, type: %d, len: %d", __FUNCTION__, nType,
  603.        packet->m_nBodySize);
  604.    /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
  605.  
  606. @@ -2856,15 +3077,15 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet)
  607.        RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
  608.        if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
  609.     {
  610. -     RTMP_Log(RTMP_LOGERROR,
  611. -            "%s: SWFVerification Type %d request not supported! Patches welcome...",
  612. -       __FUNCTION__, packet->m_body[2]);
  613. +          RTMP_Log(RTMP_LOGERROR,
  614. +                   "%s: SWFVerification Type %d request not supported, attempting to use SWFVerification Type 1! Patches welcome...",
  615. +                   __FUNCTION__, packet->m_body[2]);
  616.     }
  617.  #ifdef CRYPTO
  618.        /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
  619.  
  620.        /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
  621. -      else if (r->Link.SWFSize)
  622. +      if (r->Link.SWFSize)
  623.     {
  624.       RTMP_SendCtrl(r, 0x1B, 0, 0);
  625.     }
  626. @@ -3709,12 +3930,11 @@ HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
  627.    char hbuf[512];
  628.    int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
  629.      "Host: %.*s:%d\r\n"
  630. -    "Accept: */*\r\n"
  631. -    "User-Agent: Shockwave Flash\n"
  632. -    "Connection: Keep-Alive\n"
  633. +    "User-Agent: Shockwave Flash\r\n"
  634. +    "Connection: Keep-Alive\r\n"
  635.      "Cache-Control: no-cache\r\n"
  636. -    "Content-type: application/x-fcs\r\n"
  637. -    "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
  638. +    "Content-Type: application/x-fcs\r\n"
  639. +    "Content-Length: %d\r\n\r\n", RTMPT_cmds[cmd],
  640.      r->m_clientID.av_val ? r->m_clientID.av_val : "",
  641.      r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
  642.      r->Link.port, len);
  643. @@ -3749,6 +3969,14 @@ HTTP_read(RTMP *r, int fill)
  644.    if (!ptr)
  645.      return -1;
  646.    ptr += 4;
  647. +  int resplen = r->m_sb.sb_size - (ptr - r->m_sb.sb_start);
  648. +  if (hlen < 3584)
  649. +    while (resplen < hlen)
  650. +      {
  651. +        if (RTMPSockBuf_Fill(&r->m_sb) == -1)
  652. +          return -1;
  653. +        resplen = r->m_sb.sb_size - (ptr - r->m_sb.sb_start);
  654. +      }
  655.    r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
  656.    r->m_sb.sb_start = ptr;
  657.    r->m_unackd--;
  658. @@ -4458,3 +4686,90 @@ RTMP_Write(RTMP *r, const char *buf, int size)
  659.      }
  660.    return size+s2;
  661.  }
  662. +
  663. +static int
  664. +SendCustomCommand(RTMP *r, AVal *Command, int queue)
  665. +{
  666. +  RTMPPacket packet;
  667. +  char pbuf[512], *enc;
  668. +
  669. +  packet.m_nChannel = 0x03; /* control channel (invoke) */
  670. +  packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
  671. +  packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
  672. +  packet.m_nTimeStamp = 0;
  673. +  packet.m_nInfoField2 = 0;
  674. +  packet.m_hasAbsTimestamp = 0;
  675. +  packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
  676. +
  677. +  enc = packet.m_body;
  678. +  if (Command->av_len)
  679. +    {
  680. +      memcpy(enc, Command->av_val, Command->av_len);
  681. +      enc += Command->av_len;
  682. +    }
  683. +  else
  684. +    return FALSE;
  685. +  packet.m_nBodySize = enc - packet.m_body;
  686. +
  687. +  return RTMP_SendPacket(r, &packet, queue);
  688. +}
  689. +
  690. +static int
  691. +strsplit(char *src, int srclen, char delim, char ***params)
  692. +{
  693. +  char *sptr, *srcbeg, *srcend, *dstr;
  694. +  int count = 1, i = 0, len = 0;
  695. +
  696. +  if (src == NULL)
  697. +    return 0;
  698. +  if (!srclen)
  699. +    srclen = strlen(src);
  700. +  srcbeg = src;
  701. +  srcend = srcbeg + srclen;
  702. +  sptr = srcbeg;
  703. +
  704. +  /* count the delimiters */
  705. +  while (sptr < srcend)
  706. +    {
  707. +      if (*sptr++ == delim)
  708. +        count++;
  709. +    }
  710. +  sptr = srcbeg;
  711. +  *params = calloc(count, sizeof (size_t));
  712. +  char **param = *params;
  713. +
  714. +  for (i = 0; i < (count - 1); i++)
  715. +    {
  716. +      dstr = strchr(sptr, delim);
  717. +      len = dstr - sptr;
  718. +      param[i] = calloc(len + 1, sizeof (char));
  719. +      strncpy(param[i], sptr, len);
  720. +      sptr += len + 1;
  721. +    }
  722. +
  723. +  /* copy the last string */
  724. +  if (sptr <= srcend)
  725. +    {
  726. +      len = srclen - (sptr - srcbeg);
  727. +      param[i] = calloc(len + 1, sizeof (char));
  728. +      strncpy(param[i], sptr, len);
  729. +    }
  730. +  return count;
  731. +}
  732. +
  733. +static int
  734. +SendGetStreamLength(RTMP *r)
  735. +{
  736. +  char pbuf[256], *pend = pbuf + sizeof (pbuf), *enc;
  737. +  AVal av_Command;
  738. +
  739. +  enc = pbuf;
  740. +  enc = AMF_EncodeString(enc, pend, &av_getStreamLength);
  741. +  enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
  742. +  *enc++ = AMF_NULL;
  743. +  enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
  744. +  av_Command.av_val = pbuf;
  745. +  av_Command.av_len = enc - pbuf;
  746. +
  747. +  return SendCustomCommand(r, &av_Command, TRUE);
  748. +}
  749. diff --git librtmp/rtmp.h librtmp/rtmp.h
  750. index 6b2ae5b..96507df 100644
  751. --- librtmp/rtmp.h
  752. +++ librtmp/rtmp.h
  753. @@ -150,12 +150,14 @@ extern "C"
  754.      AVal playpath; /* passed in explicitly */
  755.      AVal tcUrl;
  756.      AVal swfUrl;
  757. +    AVal swfHash;
  758.      AVal pageUrl;
  759.      AVal app;
  760.      AVal auth;
  761.      AVal flashVer;
  762.      AVal subscribepath;
  763.      AVal usherToken;
  764. +    AVal WeebToken;
  765.      AVal token;
  766.      AMFObject extras;
  767.      int edepth;
  768. @@ -172,9 +174,14 @@ extern "C"
  769.      int lFlags;
  770.  
  771.      int swfAge;
  772. +    int swfSize;
  773.  
  774.      int protocol;
  775. +    int ConnectPacket;
  776. +    int CombineConnectPacket;
  777.      int timeout;       /* connection timeout in seconds */
  778. +    AVal Extras;
  779. +    AVal HandshakeResponse;
  780.  
  781.      unsigned short socksport;
  782.      unsigned short port;
  783. @@ -299,6 +306,7 @@ extern "C"
  784.             AVal *flashVer,
  785.             AVal *subscribepath,
  786.             AVal *usherToken,
  787. +           AVal *WeebToken,
  788.             int dStart,
  789.             int dStop, int bLiveStream, long int timeout);
  790.  
  791. diff --git librtmp/rtmp_sys.h librtmp/rtmp_sys.h
  792. index c3fd4a6..665dcd1 100644
  793. --- librtmp/rtmp_sys.h
  794. +++ librtmp/rtmp_sys.h
  795. @@ -71,7 +71,7 @@ typedef struct tls_ctx {
  796.  #define TLS_CTX tls_ctx *
  797.  #define TLS_client(ctx,s)  s = malloc(sizeof(ssl_context)); ssl_init(s);\
  798.     ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\
  799. -   ssl_set_rng(s, havege_rand, &ctx->hs);\
  800. +   ssl_set_rng(s, havege_random, &ctx->hs);\
  801.     ssl_set_ciphersuites(s, ssl_default_ciphersuites);\
  802.     ssl_set_session(s, 1, 600, &ctx->ssn)
  803.  #define TLS_setfd(s,fd)    ssl_set_bio(s, net_recv, &fd, net_send, &fd)
  804. diff --git rtmpdump.c rtmpdump.c
  805. index 34bfdba..02c9781 100644
  806. --- rtmpdump.c
  807. +++ rtmpdump.c
  808. @@ -697,6 +697,8 @@ void usage(char *prog)
  809.       RTMP_LogPrintf
  810.         ("--jtv|-j JSON           Authentication token for Justin.tv legacy servers\n");
  811.       RTMP_LogPrintf
  812. +       ("--weeb|-J string        Authentication token for weeb.tv servers\n");
  813. +     RTMP_LogPrintf
  814.         ("--hashes|-#             Display progress with hashes, not with the byte counter\n");
  815.       RTMP_LogPrintf
  816.         ("--buffer|-b             Buffer time in milliseconds (default: %u)\n",
  817. @@ -743,7 +745,8 @@ main(int argc, char **argv)
  818.    AVal hostname = { 0, 0 };
  819.    AVal playpath = { 0, 0 };
  820.    AVal subscribepath = { 0, 0 };
  821. -  AVal usherToken = { 0, 0 }; //Justin.tv auth token
  822. +  AVal usherToken = { 0, 0 }; // Justin.tv auth token
  823. +  AVal WeebToken = { 0, 0 };  // Weeb.tv auth token
  824.    int port = -1;
  825.    int protocol = RTMP_PROTOCOL_UNDEFINED;
  826.    int retries = 0;
  827. @@ -846,12 +849,13 @@ main(int argc, char **argv)
  828.      {"quiet", 0, NULL, 'q'},
  829.      {"verbose", 0, NULL, 'V'},
  830.      {"jtv", 1, NULL, 'j'},
  831. +    {"weeb", 1, NULL, 'J'},
  832.      {0, 0, 0, 0}
  833.    };
  834.  
  835.    while ((opt =
  836.       getopt_long(argc, argv,
  837. -             "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:",
  838. +             "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:",
  839.               longopts, NULL)) != -1)
  840.      {
  841.        switch (opt)
  842. @@ -1061,6 +1065,9 @@ main(int argc, char **argv)
  843.     case 'j':
  844.       STR2AVAL(usherToken, optarg);
  845.       break;
  846. +   case 'J':
  847. +     STR2AVAL(WeebToken, optarg);
  848. +     break;
  849.     default:
  850.       RTMP_LogPrintf("unknown option: %c\n", opt);
  851.       usage(argv[0]);
  852. @@ -1152,14 +1159,14 @@ main(int argc, char **argv)
  853.  
  854.    if (tcUrl.av_len == 0)
  855.      {
  856. -     tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) +
  857. -       hostname.av_len + app.av_len + sizeof("://:65535/");
  858. +      tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) +
  859. +              hostname.av_len + app.av_len + sizeof ("://:65535/");
  860.        tcUrl.av_val = (char *) malloc(tcUrl.av_len);
  861. -     if (!tcUrl.av_val)
  862. -       return RD_FAILED;
  863. +      if (!tcUrl.av_val)
  864. +        return RD_FAILED;
  865.        tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s",
  866. -          RTMPProtocolStringsLower[protocol], hostname.av_len,
  867. -          hostname.av_val, port, app.av_len, app.av_val);
  868. +                              RTMPProtocolStringsLower[protocol], hostname.av_len,
  869. +                              hostname.av_val, port, app.av_len, app.av_val);
  870.      }
  871.  
  872.    int first = 1;
  873. @@ -1178,7 +1185,7 @@ main(int argc, char **argv)
  874.  
  875.    RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
  876.            &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
  877. -          &flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout);
  878. +          &flashVer, &subscribepath, &usherToken, &WeebToken, dSeek, dStopOffset, bLiveStream, timeout);
  879.  
  880.    /* Try to keep the stream moving if it pauses on us */
  881.    if (!bLiveStream && !(protocol & RTMP_FEATURE_HTTP))
  882. diff --git rtmpgw.c rtmpgw.c
  883. index 0cf56bb..cd4396d 100644
  884. --- rtmpgw.c
  885. +++ rtmpgw.c
  886. @@ -95,7 +95,8 @@ typedef struct
  887.    AVal flashVer;
  888.    AVal token;
  889.    AVal subscribepath;
  890. -  AVal usherToken; //Justin.tv auth token
  891. +  AVal usherToken; // Justin.tv auth token
  892. +  AVal WeebToken;  // Weeb.tv auth token
  893.    AVal sockshost;
  894.    AMFObject extras;
  895.    int edepth;
  896. @@ -553,7 +554,7 @@ void processTCPrequest(STREAMING_SERVER * server,   // server socket and state (ou
  897.    RTMP_Init(&rtmp);
  898.    RTMP_SetBufferMS(&rtmp, req.bufferTime);
  899.    RTMP_SetupStream(&rtmp, req.protocol, &req.hostname, req.rtmpport, &req.sockshost,
  900. -          &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,
  901. +          &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,
  902.            req.bLiveStream, req.timeout);
  903.    /* backward compatibility, we always sent this as true before */
  904.    if (req.auth.av_len)
  905. @@ -957,6 +958,9 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req)
  906.      case 'j':
  907.        STR2AVAL(req->usherToken, arg);
  908.        break;
  909. +    case 'J':
  910. +      STR2AVAL(req->WeebToken, arg);
  911. +      break;
  912.      default:
  913.        RTMP_LogPrintf("unknown option: %c, arg: %s\n", opt, arg);
  914.        return FALSE;
  915. @@ -1028,6 +1032,7 @@ main(int argc, char **argv)
  916.      {"quiet", 0, NULL, 'q'},
  917.      {"verbose", 0, NULL, 'V'},
  918.      {"jtv", 1, NULL, 'j'},
  919. +    {"weeb", 1, NULL, 'J'},
  920.      {0, 0, 0, 0}
  921.    };
  922.  
  923. @@ -1040,7 +1045,7 @@ main(int argc, char **argv)
  924.  
  925.    while ((opt =
  926.       getopt_long(argc, argv,
  927. -             "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,
  928. +             "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,
  929.               NULL)) != -1)
  930.      {
  931.        switch (opt)
  932. @@ -1103,6 +1108,8 @@ main(int argc, char **argv)
  933.       RTMP_LogPrintf
  934.         ("--jtv|-j JSON           Authentication token for Justin.tv legacy servers\n");
  935.       RTMP_LogPrintf
  936. +       ("--weeb|-J string        Authentication token for weeb.tv servers\n");
  937. +     RTMP_LogPrintf
  938.         ("--buffer|-b             Buffer time in milliseconds (default: %u)\n\n",
  939.          defaultRTMPRequest.bufferTime);
  940.  
  941. diff --git rtmpsrv.c rtmpsrv.c
  942. index b662d54..0b001be 100644
  943. --- rtmpsrv.c
  944. +++ rtmpsrv.c
  945. @@ -96,9 +96,19 @@ STREAMING_SERVER *rtmpServer = 0;    // server structure pointer
  946.  STREAMING_SERVER *startStreaming(const char *address, int port);
  947.  void stopStreaming(STREAMING_SERVER * server);
  948.  void AVreplace(AVal *src, const AVal *orig, const AVal *repl);
  949. +char *strreplace(char *srcstr, int srclen, char *orig, char *repl);
  950. +int file_exists(const char *fname);
  951. +int SendCheckBWResponse(RTMP *r, double txn);
  952. +AVal StripParams(AVal *src);
  953.  
  954.  static const AVal av_dquote = AVC("\"");
  955.  static const AVal av_escdquote = AVC("\\\"");
  956. +#ifdef WIN32
  957. +static const AVal av_caret = AVC("^");
  958. +static const AVal av_esccaret = AVC("^^");
  959. +static const AVal av_pipe = AVC("|");
  960. +static const AVal av_escpipe = AVC("^|");
  961. +#endif
  962.  
  963.  typedef struct
  964.  {
  965. @@ -167,6 +177,8 @@ SAVC(level);
  966.  SAVC(code);
  967.  SAVC(description);
  968.  SAVC(secureToken);
  969. +SAVC(_checkbw);
  970. +SAVC(_onbwdone);
  971.  
  972.  static int
  973.  SendConnectResult(RTMP *r, double txn)
  974. @@ -271,7 +283,7 @@ static int
  975.  SendPlayStart(RTMP *r)
  976.  {
  977.    RTMPPacket packet;
  978. -  char pbuf[512], *pend = pbuf+sizeof(pbuf);
  979. +  char pbuf[1024], *pend = pbuf + sizeof (pbuf);
  980.  
  981.    packet.m_nChannel = 0x03;     // control channel (invoke)
  982.    packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */
  983. @@ -303,7 +315,7 @@ static int
  984.  SendPlayStop(RTMP *r)
  985.  {
  986.    RTMPPacket packet;
  987. -  char pbuf[512], *pend = pbuf+sizeof(pbuf);
  988. +  char pbuf[1024], *pend = pbuf + sizeof (pbuf);
  989.  
  990.    packet.m_nChannel = 0x03;     // control channel (invoke)
  991.    packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */
  992. @@ -331,6 +343,33 @@ SendPlayStop(RTMP *r)
  993.    return RTMP_SendPacket(r, &packet, FALSE);
  994.  }
  995.  
  996. +int
  997. +SendCheckBWResponse(RTMP *r, double txn)
  998. +{
  999. +  RTMPPacket packet;
  1000. +  char pbuf[256], *pend = pbuf + sizeof (pbuf);
  1001. +  char *enc;
  1002. +
  1003. +  packet.m_nChannel = 0x03; /* control channel (invoke) */
  1004. +  packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
  1005. +  packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
  1006. +  packet.m_nTimeStamp = 0;
  1007. +  packet.m_nInfoField2 = 0;
  1008. +  packet.m_hasAbsTimestamp = 0;
  1009. +  packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
  1010. +
  1011. +  enc = packet.m_body;
  1012. +  enc = AMF_EncodeString(enc, pend, &av__onbwdone);
  1013. +  enc = AMF_EncodeNumber(enc, pend, txn);
  1014. +  *enc++ = AMF_NULL;
  1015. +  enc = AMF_EncodeNumber(enc, pend, 10240);
  1016. +  enc = AMF_EncodeNumber(enc, pend, 10240);
  1017. +
  1018. +  packet.m_nBodySize = enc - packet.m_body;
  1019. +
  1020. +  return RTMP_SendPacket(r, &packet, FALSE);
  1021. +}
  1022. +
  1023.  static void
  1024.  spawn_dumper(int argc, AVal *av, char *cmd)
  1025.  {
  1026. @@ -585,10 +624,18 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1027.        AVal usherToken;
  1028.        AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &usherToken);
  1029.        AVreplace(&usherToken, &av_dquote, &av_escdquote);
  1030. +#ifdef WIN32
  1031. +      AVreplace(&usherToken, &av_caret, &av_esccaret);
  1032. +      AVreplace(&usherToken, &av_pipe, &av_escpipe);
  1033. +#endif
  1034.        server->arglen += 6 + usherToken.av_len;
  1035.        server->argc += 2;
  1036.        r->Link.usherToken = usherToken;
  1037.      }
  1038. +  else if (AVMATCH(&method, &av__checkbw))
  1039. +    {
  1040. +      SendCheckBWResponse(r, txn);
  1041. +    }
  1042.    else if (AVMATCH(&method, &av_play))
  1043.      {
  1044.        char *file, *p, *q, *cmd, *ptr;
  1045. @@ -602,6 +649,19 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1046.        if (obj.o_num > 5)
  1047.     r->Link.length = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 5));
  1048.        */
  1049. +#ifdef VLC
  1050. +      double StartFlag = -1000;
  1051. +#else
  1052. +      double StartFlag = 0;
  1053. +#endif
  1054. +      AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4);
  1055. +      if (!(Start->p_type == AMF_INVALID))
  1056. +        StartFlag = AMFProp_GetNumber(Start);
  1057. +      if (StartFlag < 0)
  1058. +        {
  1059. +          server->arglen += 7;
  1060. +          server->argc += 1;
  1061. +        }
  1062.        if (r->Link.tcUrl.av_len)
  1063.     {
  1064.       len = server->arglen + r->Link.playpath.av_len + 4 +
  1065. @@ -619,6 +679,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1066.       argv[argc].av_val = ptr + 1;
  1067.       argv[argc++].av_len = 2;
  1068.       argv[argc].av_val = ptr + 5;
  1069. +     r->Link.tcUrl = StripParams(&r->Link.tcUrl);
  1070.       ptr += sprintf(ptr," -r \"%s\"", r->Link.tcUrl.av_val);
  1071.       argv[argc++].av_len = r->Link.tcUrl.av_len;
  1072.  
  1073. @@ -643,6 +704,7 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1074.           argv[argc].av_val = ptr + 1;
  1075.           argv[argc++].av_len = 2;
  1076.           argv[argc].av_val = ptr + 5;
  1077. +         r->Link.swfUrl = StripParams(&r->Link.swfUrl);
  1078.           ptr += sprintf(ptr, " -W \"%s\"", r->Link.swfUrl.av_val);
  1079.           argv[argc++].av_len = r->Link.swfUrl.av_len;
  1080.         }
  1081. @@ -665,10 +727,17 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1082.           r->Link.usherToken.av_val = NULL;
  1083.           r->Link.usherToken.av_len = 0;
  1084.         }
  1085. -     if (r->Link.extras.o_num) {
  1086. -       ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc);
  1087. -       AMF_Reset(&r->Link.extras);
  1088. -     }
  1089. +          if (StartFlag < 0)
  1090. +            {
  1091. +              argv[argc].av_val = ptr + 1;
  1092. +              argv[argc++].av_len = 6;
  1093. +              ptr += sprintf(ptr, " --live");
  1094. +            }
  1095. +          if (r->Link.extras.o_num)
  1096. +            {
  1097. +              ptr = dumpAMF(&r->Link.extras, ptr, argv, &argc);
  1098. +              AMF_Reset(&r->Link.extras);
  1099. +            }
  1100.       argv[argc].av_val = ptr + 1;
  1101.       argv[argc++].av_len = 2;
  1102.       argv[argc].av_val = ptr + 5;
  1103. @@ -676,7 +745,13 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1104.         r->Link.playpath.av_len, r->Link.playpath.av_val);
  1105.       argv[argc++].av_len = r->Link.playpath.av_len;
  1106.  
  1107. -     av = r->Link.playpath;
  1108. +          if (r->Link.playpath.av_len)
  1109. +            av = r->Link.playpath;
  1110. +          else
  1111. +            {
  1112. +              av.av_val = "file";
  1113. +              av.av_len = 4;
  1114. +            }
  1115.       /* strip trailing URL parameters */
  1116.       q = memchr(av.av_val, '?', av.av_len);
  1117.       if (q)
  1118. @@ -728,7 +803,14 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1119.       argv[argc++].av_len = 2;
  1120.       argv[argc].av_val = file;
  1121.       argv[argc].av_len = av.av_len;
  1122. +#ifdef VLC
  1123. +          if (file_exists("C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe"))
  1124. +            ptr += sprintf(ptr, " | %s -", "\"C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe\"");
  1125. +          else
  1126. +            ptr += sprintf(ptr, " | %s -", "\"C:\\Program Files\\VideoLAN\\VLC\\vlc.exe\"");
  1127. +#else
  1128.       ptr += sprintf(ptr, " -o %s", file);
  1129. +#endif
  1130.       now = RTMP_GetTime();
  1131.       if (now - server->filetime < DUPTIME && AVMATCH(&argv[argc], &server->filename))
  1132.         {
  1133. @@ -742,7 +824,23 @@ ServeInvoke(STREAMING_SERVER *server, RTMP * r, RTMPPacket *packet, unsigned int
  1134.           server->filetime = now;
  1135.           free(server->filename.av_val);
  1136.           server->filename = argv[argc++];
  1137. +#ifdef VLC
  1138. +              FILE *vlc_cmdfile = fopen("VLC.bat", "w");
  1139. +              char *vlc_batchcmd = strreplace(cmd, 0, "%", "%%");
  1140. +              fprintf(vlc_cmdfile, "%s\n", vlc_batchcmd);
  1141. +              fclose(vlc_cmdfile);
  1142. +              free(vlc_batchcmd);
  1143. +              spawn_dumper(argc, argv, "VLC.bat");
  1144. +#else
  1145.           spawn_dumper(argc, argv, cmd);
  1146. +#endif
  1147. +
  1148. +#ifdef WIN32
  1149. +              // Dump command to batch file
  1150. +              FILE *cmdfile = fopen("Command.bat", "a");
  1151. +              fprintf(cmdfile, "%s\n", cmd);
  1152. +              fclose(cmdfile);
  1153. +#endif
  1154.         }
  1155.  
  1156.       free(cmd);
  1157. @@ -1142,6 +1240,99 @@ main(int argc, char **argv)
  1158.    return nStatus;
  1159.  }
  1160.  
  1161. +char *
  1162. +strreplace(char *srcstr, int srclen, char *orig, char *repl)
  1163. +{
  1164. +  char *ptr = NULL, *sptr = srcstr;
  1165. +  int origlen = strlen(orig);
  1166. +  int repllen = strlen(repl);
  1167. +  if (!srclen)
  1168. +    srclen = strlen(srcstr);
  1169. +  char *srcend = srcstr + srclen;
  1170. +  int dstbuffer = srclen / origlen * repllen;
  1171. +  if (dstbuffer < srclen)
  1172. +    dstbuffer = srclen;
  1173. +  char *dststr = calloc(dstbuffer + 1, sizeof (char));
  1174. +  char *dptr = dststr;
  1175. +
  1176. +  if ((ptr = strstr(srcstr, orig)))
  1177. +    {
  1178. +      while (ptr < srcend && (ptr = strstr(sptr, orig)))
  1179. +        {
  1180. +          int len = ptr - sptr;
  1181. +          memcpy(dptr, sptr, len);
  1182. +          sptr += len + origlen;
  1183. +          dptr += len;
  1184. +          memcpy(dptr, repl, repllen);
  1185. +          dptr += repllen;
  1186. +        }
  1187. +      memcpy(dptr, sptr, srcend - sptr);
  1188. +      return dststr;
  1189. +    }
  1190. +
  1191. +  memcpy(dststr, srcstr, srclen);
  1192. +  return dststr;
  1193. +}
  1194. +
  1195. +AVal
  1196. +StripParams(AVal *src)
  1197. +{
  1198. +  AVal str;
  1199. +  if (src->av_val)
  1200. +    {
  1201. +      str.av_val = calloc(src->av_len + 1, sizeof (char));
  1202. +      strncpy(str.av_val, src->av_val, src->av_len);
  1203. +      str.av_len = src->av_len;
  1204. +      char *start = str.av_val;
  1205. +      char *end = start + str.av_len;
  1206. +      char *ptr = start;
  1207. +
  1208. +      while (ptr < end)
  1209. +        {
  1210. +          if (*ptr == '?')
  1211. +            {
  1212. +              str.av_len = ptr - start;
  1213. +              break;
  1214. +            }
  1215. +          ptr++;
  1216. +        }
  1217. +      memset(start + str.av_len, 0, 1);
  1218. +
  1219. +      char *dynamic = strstr(start, "[[DYNAMIC]]");
  1220. +      if (dynamic)
  1221. +        {
  1222. +          dynamic -= 1;
  1223. +          memset(dynamic, 0, 1);
  1224. +          str.av_len = dynamic - start;
  1225. +          end = start + str.av_len;
  1226. +        }
  1227. +
  1228. +      char *import = strstr(start, "[[IMPORT]]");
  1229. +      if (import)
  1230. +        {
  1231. +          str.av_val = import + 11;
  1232. +          strcpy(start, "http://");
  1233. +          str.av_val = strcat(start, str.av_val);
  1234. +          str.av_len = strlen(str.av_val);
  1235. +        }
  1236. +      return str;
  1237. +    }
  1238. +  str = *src;
  1239. +  return str;
  1240. +}
  1241. +
  1242. +int
  1243. +file_exists(const char *fname)
  1244. +{
  1245. +  FILE *file;
  1246. +  if ((file = fopen(fname, "r")))
  1247. +    {
  1248. +      fclose(file);
  1249. +      return 1;
  1250. +    }
  1251. +  return 0;
  1252. +}
  1253. +
  1254.  void
  1255.  AVreplace(AVal *src, const AVal *orig, const AVal *repl)
  1256.  {
  1257. diff --git rtmpsuck.c rtmpsuck.c
  1258. index e886179..f8cfb7c 100644
  1259. --- rtmpsuck.c
  1260. +++ rtmpsuck.c
  1261. @@ -143,15 +143,18 @@ SAVC(onStatus);
  1262.  SAVC(close);
  1263.  static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
  1264.  static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
  1265. -static const AVal av_NetStream_Play_StreamNotFound =
  1266. -AVC("NetStream.Play.StreamNotFound");
  1267. -static const AVal av_NetConnection_Connect_InvalidApp =
  1268. -AVC("NetConnection.Connect.InvalidApp");
  1269. +static const AVal av_NetStream_Play_StreamNotFound = AVC("NetStream.Play.StreamNotFound");
  1270. +static const AVal av_NetConnection_Connect_InvalidApp = AVC("NetConnection.Connect.InvalidApp");
  1271.  static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
  1272.  static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
  1273.  static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
  1274. +static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
  1275.  
  1276.  static const char *cst[] = { "client", "server" };
  1277. +char *dumpAMF(AMFObject *obj, char *ptr);
  1278. +char *strreplace(char *srcstr, int srclen, char *orig, char *repl);
  1279. +AVal StripParams(AVal *src);
  1280. +AVal AVcopy(AVal src);
  1281.  
  1282.  // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete'
  1283.  int
  1284. @@ -198,26 +201,29 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1285.            if (cobj.o_props[i].p_type == AMF_STRING)
  1286.              {
  1287.                pval = cobj.o_props[i].p_vu.p_aval;
  1288. -              RTMP_LogPrintf("%.*s: %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val);
  1289. +              RTMP_LogPrintf("%10.*s : %.*s\n", pname.av_len, pname.av_val, pval.av_len, pval.av_val);
  1290.              }
  1291.            if (AVMATCH(&pname, &av_app))
  1292.              {
  1293. -              server->rc.Link.app = pval;
  1294. +              server->rc.Link.app = AVcopy(pval);
  1295.                pval.av_val = NULL;
  1296.              }
  1297.            else if (AVMATCH(&pname, &av_flashVer))
  1298.              {
  1299. -              server->rc.Link.flashVer = pval;
  1300. +              server->rc.Link.flashVer = AVcopy(pval);
  1301.                pval.av_val = NULL;
  1302.              }
  1303.            else if (AVMATCH(&pname, &av_swfUrl))
  1304.              {
  1305.  #ifdef CRYPTO
  1306.                if (pval.av_val)
  1307. -           RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize,
  1308. -         (unsigned char *)server->rc.Link.SWFHash, 30);
  1309. +                {
  1310. +                  AVal swfUrl = StripParams(&pval);
  1311. +                  RTMP_HashSWF(swfUrl.av_val, &server->rc.Link.SWFSize,
  1312. +                               (unsigned char *) server->rc.Link.SWFHash, 30);
  1313. +                }
  1314.  #endif
  1315. -              server->rc.Link.swfUrl = pval;
  1316. +              server->rc.Link.swfUrl = AVcopy(pval);
  1317.                pval.av_val = NULL;
  1318.              }
  1319.            else if (AVMATCH(&pname, &av_tcUrl))
  1320. @@ -225,7 +231,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1321.                char *r1 = NULL, *r2;
  1322.                int len;
  1323.  
  1324. -              server->rc.Link.tcUrl = pval;
  1325. +              server->rc.Link.tcUrl = AVcopy(pval);
  1326.                if ((pval.av_val[0] | 0x40) == 'r' &&
  1327.                    (pval.av_val[1] | 0x40) == 't' &&
  1328.                    (pval.av_val[2] | 0x40) == 'm' &&
  1329. @@ -267,7 +273,7 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1330.              }
  1331.            else if (AVMATCH(&pname, &av_pageUrl))
  1332.              {
  1333. -              server->rc.Link.pageUrl = pval;
  1334. +              server->rc.Link.pageUrl = AVcopy(pval);
  1335.                pval.av_val = NULL;
  1336.              }
  1337.            else if (AVMATCH(&pname, &av_audioCodecs))
  1338. @@ -287,14 +293,21 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1339.            if (pval.av_val)
  1340.              free(pval.av_val);
  1341.          }
  1342. +
  1343.        if (obj.o_num > 3)
  1344.          {
  1345. -          if (AMFProp_GetBoolean(&obj.o_props[3]))
  1346. -            server->rc.Link.lFlags |= RTMP_LF_AUTH;
  1347. -          if (obj.o_num > 4)
  1348. -          {
  1349. -            AMFProp_GetString(&obj.o_props[4], &server->rc.Link.auth);
  1350. -          }
  1351. +          int i = obj.o_num - 3;
  1352. +          server->rc.Link.extras.o_num = i;
  1353. +          server->rc.Link.extras.o_props = malloc(i * sizeof (AMFObjectProperty));
  1354. +          memcpy(server->rc.Link.extras.o_props, obj.o_props + 3, i * sizeof (AMFObjectProperty));
  1355. +          obj.o_num = 3;
  1356. +        }
  1357. +
  1358. +      if (server->rc.Link.extras.o_num)
  1359. +        {
  1360. +          server->rc.Link.Extras.av_val = calloc(1024, sizeof (char));
  1361. +          dumpAMF(&server->rc.Link.extras, server->rc.Link.Extras.av_val);
  1362. +          server->rc.Link.Extras.av_len = strlen(server->rc.Link.Extras.av_val);
  1363.          }
  1364.  
  1365.        if (!RTMP_Connect(&server->rc, pack))
  1366. @@ -303,6 +316,16 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1367.            return 1;
  1368.          }
  1369.        server->rc.m_bSendCounter = FALSE;
  1370. +
  1371. +      if (server->rc.Link.extras.o_props)
  1372. +        {
  1373. +          AMF_Reset(&server->rc.Link.extras);
  1374. +        }
  1375. +    }
  1376. +  else if (AVMATCH(&method, &av_NetStream_Authenticate_UsherToken))
  1377. +    {
  1378. +      AMFProp_GetString(AMF_GetProp(&obj, NULL, 3), &server->rc.Link.usherToken);
  1379. +      RTMP_LogPrintf("%10s : %.*s\n", "usherToken", server->rc.Link.usherToken.av_len, server->rc.Link.usherToken.av_val);
  1380.      }
  1381.    else if (AVMATCH(&method, &av_play))
  1382.      {
  1383. @@ -323,6 +346,12 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1384.        if (!av.av_val)
  1385.          goto out;
  1386.  
  1387. +      double StartFlag = 0;
  1388. +      AMFObjectProperty *Start = AMF_GetProp(&obj, NULL, 4);
  1389. +      if (!(Start->p_type == AMF_INVALID))
  1390. +        StartFlag = AMFProp_GetNumber(Start);
  1391. +      RTMP_LogPrintf("%10s : %s\n", "live", (StartFlag < 0) ? "yes" : "no");
  1392. +
  1393.        /* check for duplicates */
  1394.        for (fl = server->f_head; fl; fl=fl->f_next)
  1395.          {
  1396. @@ -372,9 +401,51 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
  1397.        for (p=file; *p; p++)
  1398.          if (*p == ':')
  1399.            *p = '_';
  1400. -      RTMP_LogPrintf("Playpath: %.*s\nSaving as: %s\n",
  1401. -        server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val,
  1402. -        file);
  1403. +      RTMP_LogPrintf("%10s : %.*s\n%10s : %s\n", "Playpath", server->rc.Link.playpath.av_len,
  1404. +                     server->rc.Link.playpath.av_val, "Saving as", file);
  1405. +
  1406. +#ifdef WIN32
  1407. +      // Dump command to batch file
  1408. +      char *cmd = NULL, *ptr = NULL;
  1409. +      AVal swfUrl, tcUrl;
  1410. +
  1411. +      cmd = calloc(2048, sizeof (char));
  1412. +      ptr = cmd;
  1413. +      tcUrl = StripParams(&server->rc.Link.tcUrl);
  1414. +      swfUrl = StripParams(&server->rc.Link.swfUrl);
  1415. +      ptr += sprintf(ptr, "rtmpdump -r \"%.*s\" -a \"%.*s\" -f \"%.*s\" -W \"%.*s\" -p \"%.*s\"",
  1416. +                     tcUrl.av_len, tcUrl.av_val,
  1417. +                     server->rc.Link.app.av_len, server->rc.Link.app.av_val,
  1418. +                     server->rc.Link.flashVer.av_len, server->rc.Link.flashVer.av_val,
  1419. +                     swfUrl.av_len, swfUrl.av_val,
  1420. +                     server->rc.Link.pageUrl.av_len, server->rc.Link.pageUrl.av_val);
  1421. +
  1422. +      if (server->rc.Link.usherToken.av_val)
  1423. +        {
  1424. +          char *usherToken = strreplace(server->rc.Link.usherToken.av_val, server->rc.Link.usherToken.av_len, "\"", "\\\"");
  1425. +          usherToken = strreplace(usherToken, 0, "^", "^^");
  1426. +          usherToken = strreplace(usherToken, 0, "|", "^|");
  1427. +          ptr += sprintf(ptr, " --jtv \"%s\"", usherToken);
  1428. +          free(usherToken);
  1429. +        }
  1430. +
  1431. +      if (server->rc.Link.Extras.av_len)
  1432. +        {
  1433. +          ptr += sprintf(ptr, "%.*s", server->rc.Link.Extras.av_len, server->rc.Link.Extras.av_val);
  1434. +        }
  1435. +
  1436. +      if (StartFlag < 0)
  1437. +        ptr += sprintf(ptr, "%s", " --live");
  1438. +      ptr += sprintf(ptr, " -y \"%.*s\"", server->rc.Link.playpath.av_len, server->rc.Link.playpath.av_val);
  1439. +      ptr += sprintf(ptr, " -o \"%s.flv\"\n", file);
  1440. +
  1441. +      FILE *cmdfile = fopen("Command.bat", "a");
  1442. +      fprintf(cmdfile, "%s", cmd);
  1443. +      fclose(cmdfile);
  1444. +
  1445. +      free(cmd);
  1446. +#endif
  1447. +
  1448.        out = fopen(file, "wb");
  1449.        free(file);
  1450.        if (!out)
  1451. @@ -1196,3 +1267,145 @@ main(int argc, char **argv)
  1452.  #endif
  1453.    return nStatus;
  1454.  }
  1455. +
  1456. +char *
  1457. +dumpAMF(AMFObject *obj, char *ptr)
  1458. +{
  1459. +  int i;
  1460. +  const char opt[] = "NBSO Z";
  1461. +
  1462. +  for (i = 0; i < obj->o_num; i++)
  1463. +    {
  1464. +      AMFObjectProperty *p = &obj->o_props[i];
  1465. +      if (p->p_type > 5)
  1466. +        continue;
  1467. +      ptr += sprintf(ptr, " -C ");
  1468. +      if (p->p_name.av_val)
  1469. +        *ptr++ = 'N';
  1470. +      *ptr++ = opt[p->p_type];
  1471. +      *ptr++ = ':';
  1472. +      if (p->p_name.av_val)
  1473. +        ptr += sprintf(ptr, "%.*s:", p->p_name.av_len, p->p_name.av_val);
  1474. +      switch (p->p_type)
  1475. +        {
  1476. +        case AMF_BOOLEAN:
  1477. +          *ptr++ = p->p_vu.p_number != 0 ? '1' : '0';
  1478. +          break;
  1479. +        case AMF_STRING:
  1480. +          memcpy(ptr, p->p_vu.p_aval.av_val, p->p_vu.p_aval.av_len);
  1481. +          ptr += p->p_vu.p_aval.av_len;
  1482. +          break;
  1483. +        case AMF_NUMBER:
  1484. +          ptr += sprintf(ptr, "%f", p->p_vu.p_number);
  1485. +          break;
  1486. +        case AMF_OBJECT:
  1487. +          *ptr++ = '1';
  1488. +          ptr = dumpAMF(&p->p_vu.p_object, ptr);
  1489. +          ptr += sprintf(ptr, " -C O:0");
  1490. +          break;
  1491. +        case AMF_NULL:
  1492. +        default:
  1493. +          break;
  1494. +        }
  1495. +    }
  1496. +  return ptr;
  1497. +}
  1498. +
  1499. +char *
  1500. +strreplace(char *srcstr, int srclen, char *orig, char *repl)
  1501. +{
  1502. +  char *ptr = NULL, *sptr = srcstr;
  1503. +  int origlen = strlen(orig);
  1504. +  int repllen = strlen(repl);
  1505. +  if (!srclen)
  1506. +    srclen = strlen(srcstr);
  1507. +  char *srcend = srcstr + srclen;
  1508. +  int dstbuffer = srclen / origlen * repllen;
  1509. +  if (dstbuffer < srclen)
  1510. +    dstbuffer = srclen;
  1511. +  char *dststr = calloc(dstbuffer + 1, sizeof (char));
  1512. +  char *dptr = dststr;
  1513. +
  1514. +  if ((ptr = strstr(srcstr, orig)))
  1515. +    {
  1516. +      while (ptr < srcend && (ptr = strstr(sptr, orig)))
  1517. +        {
  1518. +          int len = ptr - sptr;
  1519. +          memcpy(dptr, sptr, len);
  1520. +          sptr += len + origlen;
  1521. +          dptr += len;
  1522. +          memcpy(dptr, repl, repllen);
  1523. +          dptr += repllen;
  1524. +        }
  1525. +      memcpy(dptr, sptr, srcend - sptr);
  1526. +      return dststr;
  1527. +    }
  1528. +
  1529. +  memcpy(dststr, srcstr, srclen);
  1530. +  return dststr;
  1531. +}
  1532. +
  1533. +AVal
  1534. +StripParams(AVal *src)
  1535. +{
  1536. +  AVal str;
  1537. +  if (src->av_val)
  1538. +    {
  1539. +      str.av_val = calloc(src->av_len + 1, sizeof (char));
  1540. +      strncpy(str.av_val, src->av_val, src->av_len);
  1541. +      str.av_len = src->av_len;
  1542. +      char *start = str.av_val;
  1543. +      char *end = start + str.av_len;
  1544. +      char *ptr = start;
  1545. +
  1546. +      while (ptr < end)
  1547. +        {
  1548. +          if (*ptr == '?')
  1549. +            {
  1550. +              str.av_len = ptr - start;
  1551. +              break;
  1552. +            }
  1553. +          ptr++;
  1554. +        }
  1555. +      memset(start + str.av_len, 0, 1);
  1556. +
  1557. +      char *dynamic = strstr(start, "[[DYNAMIC]]");
  1558. +      if (dynamic)
  1559. +        {
  1560. +          dynamic -= 1;
  1561. +          memset(dynamic, 0, 1);
  1562. +          str.av_len = dynamic - start;
  1563. +          end = start + str.av_len;
  1564. +        }
  1565. +
  1566. +      char *import = strstr(start, "[[IMPORT]]");
  1567. +      if (import)
  1568. +        {
  1569. +          str.av_val = import + 11;
  1570. +          strcpy(start, "http://");
  1571. +          str.av_val = strcat(start, str.av_val);
  1572. +          str.av_len = strlen(str.av_val);
  1573. +        }
  1574. +      return str;
  1575. +    }
  1576. +  str = *src;
  1577. +  return str;
  1578. +}
  1579. +
  1580. +AVal
  1581. +AVcopy(AVal src)
  1582. +{
  1583. +  AVal dst;
  1584. +  if (src.av_len)
  1585. +    {
  1586. +      dst.av_val = malloc(src.av_len);
  1587. +      memcpy(dst.av_val, src.av_val, src.av_len);
  1588. +      dst.av_len = src.av_len;
  1589. +    }
  1590. +  else
  1591. +    {
  1592. +      dst.av_val = NULL;
  1593. +      dst.av_len = 0;
  1594. +    }
  1595. +  return dst;
  1596. +}
Add Comment
Please, Sign In to add comment