Option restructuring, allow most options to be passed along
authorhyc <hyc@400ebc74-4327-4243-bc38-086b20814532>
Sat, 27 Mar 2010 05:35:04 +0000 (05:35 +0000)
committerhyc <hyc@400ebc74-4327-4243-bc38-086b20814532>
Sat, 27 Mar 2010 05:35:04 +0000 (05:35 +0000)
with the RTMP URL, clean up

git-svn-id: svn://svn.mplayerhq.hu/rtmpdump/trunk@405 400ebc74-4327-4243-bc38-086b20814532

librtmp/Makefile
librtmp/handshake.h
librtmp/rtmp.c
librtmp/rtmp.h
rtmpdump.c
rtmpgw.c
rtmpsuck.c

index 8e037b5..7de910e 100644 (file)
@@ -32,7 +32,7 @@ log.o: log.c log.h Makefile
 rtmp.o: rtmp.c rtmp.h rtmp_sys.h handshake.h dh.h log.h amf.h Makefile
 amf.o: amf.c amf.h bytes.h log.h Makefile
 hashswf.o: hashswf.c http.h rtmp.h rtmp_sys.h Makefile
-parseurl.o: parseurl.c rtmp_sys.h log.h Makefile
+parseurl.o: parseurl.c rtmp.h rtmp_sys.h log.h Makefile
 
 librtmp.pc: librtmp.pc.in Makefile
        sed -e "s;@prefix@;$(prefix);" -e "s;@VERSION@;$(VERSION);" \
index e01d286..249a6fb 100644 (file)
@@ -346,7 +346,7 @@ HandShake(RTMP * r, bool FP9HandShake)
   char type;
   getoff *getdh, *getdig;
 
-  if (encrypted || r->Link.SWFHash.av_len)
+  if (encrypted || r->Link.SWFSize)
     FP9HandShake = true;
   else
     FP9HandShake = false;
@@ -504,7 +504,7 @@ HandShake(RTMP * r, bool FP9HandShake)
          dhposServer);
 
       /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
-      if (r->Link.SWFHash.av_len)
+      if (r->Link.SWFSize)
        {
          const char swfVerify[] = { 0x01, 0x01 };
           char *vend = r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);
@@ -512,7 +512,7 @@ HandShake(RTMP * r, bool FP9HandShake)
          memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
          AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], vend, r->Link.SWFSize);
          AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], vend, r->Link.SWFSize);
-         HMACsha256(r->Link.SWFHash.av_val, SHA256_DIGEST_LENGTH,
+         HMACsha256(r->Link.SWFHash, SHA256_DIGEST_LENGTH,
                     &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
                     SHA256_DIGEST_LENGTH, &r->Link.SWFVerificationResponse[10]);
        }
@@ -866,7 +866,7 @@ SHandShake(RTMP * r)
          dhposClient);
 
       /* generate SWFVerification token (SHA256 HMAC hash of decompressed SWF, key are the last 32 bytes of the server handshake) */
-      if (r->Link.SWFHash.av_len)
+      if (r->Link.SWFSize)
        {
          const char swfVerify[] = { 0x01, 0x01 };
           char *vend = r->Link.SWFVerificationResponse+sizeof(r->Link.SWFVerificationResponse);
@@ -874,7 +874,7 @@ SHandShake(RTMP * r)
          memcpy(r->Link.SWFVerificationResponse, swfVerify, 2);
          AMF_EncodeInt32(&r->Link.SWFVerificationResponse[2], vend, r->Link.SWFSize);
          AMF_EncodeInt32(&r->Link.SWFVerificationResponse[6], vend, r->Link.SWFSize);
-         HMACsha256(r->Link.SWFHash.av_val, SHA256_DIGEST_LENGTH,
+         HMACsha256(r->Link.SWFHash, SHA256_DIGEST_LENGTH,
                     &serversig[RTMP_SIG_SIZE - SHA256_DIGEST_LENGTH],
                     SHA256_DIGEST_LENGTH, &r->Link.SWFVerificationResponse[10]);
        }
index 19f90d8..f24c3be 100644 (file)
@@ -276,7 +276,8 @@ RTMP_UpdateBufferMS(RTMP *r)
 #else
 #define OSS    "GNU"
 #endif
-static const char DEFAULT_FLASH_VER[] = OSS " 10,0,32,18";
+#define DEF_VERSTR     OSS " 10,0,32,18"
+static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
 const AVal RTMP_DefaultFlashVer =
   { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
 
@@ -296,8 +297,8 @@ RTMP_SetupStream(RTMP *r,
                 uint32_t swfSize,
                 AVal *flashVer,
                 AVal *subscribepath,
-                double dTime,
-                uint32_t dLength, bool bLiveStream, long int timeout)
+                double dStart,
+                double dStop, bool bLiveStream, long int timeout)
 {
   RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
   RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
@@ -318,10 +319,10 @@ RTMP_SetupStream(RTMP *r,
     RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
   if (flashVer && flashVer->av_val)
     RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
-  if (dTime > 0)
-    RTMP_Log(RTMP_LOGDEBUG, "SeekTime      : %.3f sec", (double)dTime / 1000.0);
-  if (dLength > 0)
-    RTMP_Log(RTMP_LOGDEBUG, "playLength    : %.3f sec", (double)dLength / 1000.0);
+  if (dStart > 0)
+    RTMP_Log(RTMP_LOGDEBUG, "StartTime     : %.3f sec", dStart);
+  if (dStop > 0)
+    RTMP_Log(RTMP_LOGDEBUG, "StopTime      : %.3f sec", dStop);
 
   RTMP_Log(RTMP_LOGDEBUG, "live     : %s", bLiveStream ? "yes" : "no");
   RTMP_Log(RTMP_LOGDEBUG, "timeout  : %d sec", timeout);
@@ -329,16 +330,14 @@ RTMP_SetupStream(RTMP *r,
 #ifdef CRYPTO
   if (swfSHA256Hash != NULL && swfSize > 0)
     {
-      r->Link.SWFHash = *swfSHA256Hash;
+      memcpy(r->Link.SWFHash, swfSHA256Hash->av_val, sizeof(r->Link.SWFHash));
       r->Link.SWFSize = swfSize;
       RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
-      RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash.av_val, 32);
+      RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
       RTMP_Log(RTMP_LOGDEBUG, "SWFSize  : %lu", r->Link.SWFSize);
     }
   else
     {
-      r->Link.SWFHash.av_len = 0;
-      r->Link.SWFHash.av_val = NULL;
       r->Link.SWFSize = 0;
     }
 #endif
@@ -373,15 +372,18 @@ RTMP_SetupStream(RTMP *r,
   if (app && app->av_len)
     r->Link.app = *app;
   if (auth && auth->av_len)
-    r->Link.auth = *auth;
+    {
+      r->Link.auth = *auth;
+      r->Link.authflag = true;
+    }
   if (flashVer && flashVer->av_len)
     r->Link.flashVer = *flashVer;
   else
     r->Link.flashVer = RTMP_DefaultFlashVer;
   if (subscribepath && subscribepath->av_len)
     r->Link.subscribepath = *subscribepath;
-  r->Link.seekTime = dTime;
-  r->Link.length = dLength;
+  r->Link.seekTime = dStart;
+  r->Link.stopTime = dStop;
   r->Link.bLiveStream = bLiveStream;
   r->Link.timeout = timeout;
 
@@ -401,6 +403,251 @@ RTMP_SetupStream(RTMP *r,
     }
 }
 
+enum { OPT_STR=0, OPT_INT, OPT_BOOL, OPT_CONN };
+static const char *optinfo[] = {
+       "string", "integer", "boolean", "AMF" };
+
+#define OFF(x) offsetof(struct RTMP,x)
+
+static struct urlopt {
+  AVal name;
+  off_t off;
+  int otype;
+  char *use;
+} options[] = {
+  { AVC("socks"),     OFF(Link.sockshost),     OPT_STR,
+       "Use the specified SOCKS proxy" },
+  { AVC("app"),       OFF(Link.app),           OPT_STR,
+       "Name of target app on server" },
+  { AVC("tcUrl"),     OFF(Link.tcUrl),         OPT_STR,
+       "URL to played stream" },
+  { AVC("pageUrl"),   OFF(Link.pageUrl),       OPT_STR,
+       "URL of played media's web page" },
+  { AVC("swfUrl"),    OFF(Link.swfUrl),        OPT_STR,
+       "URL to player SWF file" },
+  { AVC("flashver"),  OFF(Link.flashVer),      OPT_STR,
+       "Flash version string (default " DEF_VERSTR ")" },
+  { AVC("conn"),      OFF(Link.extras),        OPT_CONN,
+       "Append arbitrary AMF data to Connect message" },
+  { AVC("playpath"),  OFF(Link.playpath),      OPT_STR,
+       "Path to target media on server" },
+  { AVC("live"),      OFF(Link.bLiveStream),   OPT_BOOL,
+       "Stream is live, no seeking possible" },
+  { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR,
+       "Stream to subscribe to" },
+  { AVC("token"),     OFF(Link.token),        OPT_STR,
+       "Key for SecureToken response" },
+  { AVC("swfVfy"),    OFF(Link.swfVfy),        OPT_BOOL,
+       "Perform SWF Verification" },
+  { AVC("swfAge"),    OFF(Link.swfAge),        OPT_INT,
+       "Number of days to use cached SWF hash" },
+  { AVC("start"),     OFF(Link.seekTime),      OPT_INT,
+       "Stream start position in milliseconds" },
+  { AVC("stop"),      OFF(Link.stopTime),      OPT_INT,
+       "Stream stop position in milliseconds" },
+  { AVC("buffer"),    OFF(m_nBufferMS),        OPT_INT,
+       "Buffer time in milliseconds" },
+  { AVC("timeout"),   OFF(Link.timeout),       OPT_INT,
+       "Session timeout in seconds" },
+  { {NULL,0}, 0, 0}
+};
+
+static const AVal truth[] = {
+       AVC("1"),
+       AVC("on"),
+       AVC("yes"),
+       AVC("true"),
+       {0,0}
+};
+
+static void RTMP_OptUsage()
+{
+  int i;
+
+  RTMP_LogPrintf("Valid RTMP options are:\n");
+  for (i=0; options[i].name.av_len; i++) {
+    RTMP_LogPrintf("%10s %-7s  %s\n", options[i].name.av_val,
+       optinfo[options[i].otype], options[i].use);
+  }
+}
+
+static int
+parseAMF(AMFObject *obj, AVal *av, int *depth)
+{
+  AMFObjectProperty prop = {{0,0}};
+  int i;
+  char *p, *arg = av->av_val;
+
+  if (arg[1] == ':')
+    {
+      p = (char *)arg+2;
+      switch(arg[0])
+        {
+        case 'B':
+          prop.p_type = AMF_BOOLEAN;
+          prop.p_vu.p_number = atoi(p);
+          break;
+        case 'S':
+          prop.p_type = AMF_STRING;
+         prop.p_vu.p_aval.av_val = p;
+         prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
+          break;
+        case 'N':
+          prop.p_type = AMF_NUMBER;
+          prop.p_vu.p_number = strtod(p, NULL);
+          break;
+        case 'Z':
+          prop.p_type = AMF_NULL;
+          break;
+        case 'O':
+          i = atoi(p);
+          if (i)
+            {
+              prop.p_type = AMF_OBJECT;
+            }
+          else
+            {
+              (*depth)--;
+              return 0;
+            }
+          break;
+        default:
+          return -1;
+        }
+    }
+  else if (arg[2] == ':' && arg[0] == 'N')
+    {
+      p = strchr(arg+3, ':');
+      if (!p || !*depth)
+        return -1;
+      prop.p_name.av_val = (char *)arg+3;
+      prop.p_name.av_len = p - (arg+3);
+
+      p++;
+      switch(arg[1])
+        {
+        case 'B':
+          prop.p_type = AMF_BOOLEAN;
+          prop.p_vu.p_number = atoi(p);
+          break;
+        case 'S':
+          prop.p_type = AMF_STRING;
+         prop.p_vu.p_aval.av_val = p;
+         prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
+          break;
+        case 'N':
+          prop.p_type = AMF_NUMBER;
+          prop.p_vu.p_number = strtod(p, NULL);
+          break;
+        case 'O':
+          prop.p_type = AMF_OBJECT;
+          break;
+        default:
+          return -1;
+        }
+    }
+  else
+    return -1;
+
+  if (*depth)
+    {
+      AMFObject *o2;
+      for (i=0; i<*depth; i++)
+        {
+          o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
+          obj = o2;
+        }
+    }
+  AMF_AddProp(obj, &prop);
+  if (prop.p_type == AMF_OBJECT)
+    (*depth)++;
+  return 0;
+}
+
+bool RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg)
+{
+  int i;
+  void *v;
+
+  for (i=0; options[i].name.av_len; i++) {
+    if (opt->av_len != options[i].name.av_len) continue;
+    if (strcasecmp(opt->av_val, options[i].name.av_val)) continue;
+    v = (char *)r + options[i].off;
+    switch(options[i].otype) {
+    case OPT_STR: {
+      AVal *aptr = v;
+      *aptr = *arg; }
+      break;
+    case OPT_INT: {
+      long l = strtol(arg->av_val, NULL, 0);
+      *(int *)v = l; }
+      break;
+    case OPT_BOOL: {
+      int j;
+      bool b = false;
+      for (j=0; truth[j].av_len; j++) {
+        if (arg->av_len != truth[j].av_len) continue;
+        if (strcasecmp(arg->av_val, truth[j].av_val)) continue;
+        b = true; break; }
+      *(bool *)v = b;
+      }
+      break;
+    case OPT_CONN:
+      if (parseAMF(&r->Link.extras, arg, &r->Link.edepth))
+        return false;
+      break;
+    }
+    break;
+  }
+  if (!options[i].name.av_len) {
+    RTMP_Log(RTMP_LOGERROR, "Unknown option %s", opt->av_val);
+    RTMP_OptUsage();
+    return false;
+  }
+
+  return true;
+}
+
+bool RTMP_SetupURL(RTMP *r, char *url)
+{
+  AVal opt, arg;
+  char *p1, *p2, *ptr = strchr(url, ' ');
+  bool ret;
+  unsigned int port = 0;
+
+  while (ptr) {
+    *ptr++ = '\0';
+    p1 = ptr;
+    p2 = strchr(p1, '=');
+    if (!p2)
+      break;
+    opt.av_val = p1;
+    opt.av_len = p2 - p1;
+    *p2++ = '\0';
+    arg.av_val = p2;
+    ptr = strchr(p2, ' ');
+    if (ptr) {
+      *ptr = '\0';
+      arg.av_len = ptr - p2;
+    } else {
+      arg.av_len = strlen(p2);
+    }
+    ret = RTMP_SetOpt(r, &opt, &arg);
+    if (!ret)
+      return ret;
+  }
+  ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
+       &port, &r->Link.playpath0, &r->Link.app);
+  if (!ret)
+    return ret;
+  r->Link.port = port;
+  r->Link.playpath = r->Link.playpath0;
+  if (r->Link.swfVfy && r->Link.swfUrl.av_len)
+    RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
+         (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
+  return true;
+}
+
 static bool
 add_addr_info(struct sockaddr_in *service, AVal *host, int port)
 {
@@ -606,15 +853,12 @@ SocksNegotiate(RTMP *r)
 }
 
 bool
-RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength)
+RTMP_ConnectStream(RTMP *r, double seekTime)
 {
   RTMPPacket packet = { 0 };
   if (seekTime >= -2.0)
     r->Link.seekTime = seekTime;
 
-  if (dLength >= 0)
-    r->Link.length = dLength;
-
   r->m_mediaChannel = 0;
 
   while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
@@ -641,16 +885,13 @@ RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength)
 }
 
 bool
-RTMP_ReconnectStream(RTMP *r, int bufferTime, double seekTime,
-                    uint32_t dLength)
+RTMP_ReconnectStream(RTMP *r, double seekTime)
 {
   RTMP_DeleteStream(r);
 
   RTMP_SendCreateStream(r);
 
-  RTMP_SetBufferMS(r, bufferTime);
-
-  return RTMP_ConnectStream(r, seekTime, dLength);
+  return RTMP_ConnectStream(r, seekTime);
 }
 
 bool
@@ -681,6 +922,7 @@ RTMP_DeleteStream(RTMP *r)
   r->m_bPlaying = false;
 
   SendDeleteStream(r, r->m_stream_id);
+  r->m_stream_id = -1;
 }
 
 int
@@ -1607,8 +1849,8 @@ SendPlay(RTMP *r)
   enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
   *enc++ = AMF_NULL;
 
-  RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%.2f, dLength=%d, sending play: %s",
-      __FUNCTION__, r->Link.seekTime, r->Link.length,
+  RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%.2f, stopTime=%.2f, sending play: %s",
+      __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
       r->Link.playpath.av_val);
   enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
   if (!enc)
@@ -1637,9 +1879,9 @@ SendPlay(RTMP *r)
   //   0: plays a frame 'start' ms away from the beginning
   //  >0: plays a live or recoded stream for 'len' milliseconds
   //enc += EncodeNumber(enc, -1.0); // len
-  if (r->Link.length)
+  if (r->Link.stopTime)
     {
-      enc = AMF_EncodeNumber(enc, pend, r->Link.length);       // len
+      enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
       if (!enc)
        return false;
     }
@@ -2230,7 +2472,7 @@ HandleCtrl(RTMP *r, const RTMPPacket *packet)
       //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
-      if (r->Link.SWFHash.av_len)
+      if (r->Link.SWFSize)
        {
          RTMP_SendCtrl(r, 0x1B, 0, 0);
        }
@@ -2866,6 +3108,9 @@ RTMP_Close(RTMP *r)
   r->m_resplen = 0;
   r->m_unackd = 0;
 
+  free(r->Link.playpath0.av_val);
+  r->Link.playpath0.av_val = NULL;
+
 #ifdef CRYPTO
   if (r->Link.dh)
     {
index fac4ac2..90f858f 100644 (file)
@@ -76,8 +76,6 @@ extern "C"
 #define RTMP_PACKET_SIZE_SMALL    2
 #define RTMP_PACKET_SIZE_MINIMUM  3
 
-  typedef unsigned char BYTE;
-
   typedef struct RTMPChunk
   {
     int c_headerSize;
@@ -88,9 +86,9 @@ extern "C"
 
   typedef struct RTMPPacket
   {
-    BYTE m_headerType;
-    BYTE m_packetType;
-    BYTE m_hasAbsTimestamp;    // timestamp absolute or relative?
+    uint8_t m_headerType;
+    uint8_t m_packetType;
+    uint8_t m_hasAbsTimestamp; // timestamp absolute or relative?
     int m_nChannel;
     uint32_t m_nTimeStamp;     // timestamp
     int32_t m_nInfoField2;     // last 4 bytes in a long header
@@ -120,10 +118,10 @@ extern "C"
   typedef struct RTMP_LNK
   {
     AVal hostname;
-    unsigned int port;
-    int protocol;
+    AVal sockshost;
 
-    AVal playpath;
+    AVal playpath0;    /* parsed from URL */
+    AVal playpath;     /* passed in explicitly */
     AVal tcUrl;
     AVal swfUrl;
     AVal pageUrl;
@@ -132,26 +130,30 @@ extern "C"
     AVal flashVer;
     AVal subscribepath;
     AVal token;
-    AVal playpath0;
     AMFObject extras;
+       int edepth;
+
+    int seekTime;
+    int stopTime;
 
-    double seekTime;
-    uint32_t length;
     bool authflag;
     bool bLiveStream;
+    bool swfVfy;
+    int swfAge;
 
+    int protocol;
     int timeout;               // number of seconds before connection times out
 
-    AVal sockshost;
     unsigned short socksport;
+    unsigned short port;
 
 #ifdef CRYPTO
     void *dh;                  // for encryption
     void *rc4keyIn;
     void *rc4keyOut;
 
-    AVal SWFHash;
     uint32_t SWFSize;
+    char SWFHash[32];
     char SWFVerificationResponse[42];
 #endif
   } RTMP_LNK;
@@ -236,10 +238,13 @@ extern "C"
 
   bool RTMP_ParseURL(const char *url, int *protocol, AVal *host,
                     unsigned int *port, AVal *playpath, AVal *app);
+
   void RTMP_ParsePlaypath(AVal *in, AVal *out);
   void RTMP_SetBufferMS(RTMP *r, int size);
   void RTMP_UpdateBufferMS(RTMP *r);
 
+  bool RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg);
+  bool RTMP_SetupURL(RTMP *r, char *url);
   void RTMP_SetupStream(RTMP *r, int protocol,
                        AVal *hostname,
                        unsigned int port,
@@ -254,8 +259,8 @@ extern "C"
                        uint32_t swfSize,
                        AVal *flashVer,
                        AVal *subscribepath,
-                       double dTime,
-                       uint32_t dLength, bool bLiveStream, long int timeout);
+                       double dStart,
+                       double dStop, bool bLiveStream, long int timeout);
 
   bool RTMP_Connect(RTMP *r, RTMPPacket *cp);
   struct sockaddr;
@@ -271,9 +276,8 @@ extern "C"
   double RTMP_GetDuration(RTMP *r);
   bool RTMP_ToggleStream(RTMP *r);
 
-  bool RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength);
-  bool RTMP_ReconnectStream(RTMP *r, int bufferTime, double seekTime,
-                           uint32_t dLength);
+  bool RTMP_ConnectStream(RTMP *r, double seekTime);
+  bool RTMP_ReconnectStream(RTMP *r, double seekTime);
   void RTMP_DeleteStream(RTMP *r);
   int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet);
   int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet);
index e464460..ead20df 100644 (file)
 #define RD_FAILED              1
 #define RD_INCOMPLETE          2
 
+#define DEF_TIMEOUT    30      /* seconds */
+#define DEF_BUFTIME    (10 * 60 * 60 * 1000)   /* 10 hours default */
+#define DEF_SKIPFRM    0
+
 // starts sockets
 bool
 InitSockets()
@@ -119,6 +123,8 @@ int hex2bin(char *str, char **hex)
 
 static const AVal av_onMetaData = AVC("onMetaData");
 static const AVal av_duration = AVC("duration");
+static const AVal av_conn = AVC("conn");
+static const AVal av_token = AVC("token");
 
 int
 OpenResumeFile(const char *flvFile,    // file name [in]
@@ -431,7 +437,7 @@ GetLastKeyframe(FILE * file,        // output file [in]
 
 int
 Download(RTMP * rtmp,          // connected RTMP object
-        FILE * file, uint32_t dSeek, uint32_t dLength, double duration, bool bResume, char *metaHeader, uint32_t nMetaHeaderSize, char *initialFrame, int initialFrameType, uint32_t nInitialFrameSize, int nSkipKeyFrames, bool bStdoutMode, bool bLiveStream, bool bHashes, bool bOverrideBufferTime, uint32_t bufferTime, double *percent)  // percentage downloaded [out]
+        FILE * file, uint32_t dSeek, uint32_t dStopOffset, double duration, bool bResume, char *metaHeader, uint32_t nMetaHeaderSize, char *initialFrame, int initialFrameType, uint32_t nInitialFrameSize, int nSkipKeyFrames, bool bStdoutMode, bool bLiveStream, bool bHashes, bool bOverrideBufferTime, uint32_t bufferTime, double *percent)      // percentage downloaded [out]
 {
   int32_t now, lastUpdate;
   int bufferSize = 64 * 1024;
@@ -484,8 +490,8 @@ Download(RTMP * rtmp,               // connected RTMP object
        }
     }
 
-  if (dLength > 0)
-    RTMP_LogPrintf("For duration: %.3f sec\n", (double) dLength / 1000.0);
+  if (dStopOffset > 0)
+    RTMP_LogPrintf("For duration: %.3f sec\n", (double) (dStopOffset - dSeek) / 1000.0);
 
   if (bResume && nInitialFrameSize > 0)
     rtmp->m_read.flags |= RTMP_READ_RESUME;
@@ -620,95 +626,81 @@ Download(RTMP * rtmp,             // connected RTMP object
 
 #define STR2AVAL(av,str)       av.av_val = str; av.av_len = strlen(av.av_val)
 
-int
-parseAMF(AMFObject *obj, const char *arg, int *depth)
+void usage(char *prog)
 {
-  AMFObjectProperty prop = {{0,0}};
-  int i;
-  char *p;
-
-  if (arg[1] == ':')
-    {
-      p = (char *)arg+2;
-      switch(arg[0])
-        {
-        case 'B':
-          prop.p_type = AMF_BOOLEAN;
-          prop.p_vu.p_number = atoi(p);
-          break;
-        case 'S':
-          prop.p_type = AMF_STRING;
-          STR2AVAL(prop.p_vu.p_aval,p);
-          break;
-        case 'N':
-          prop.p_type = AMF_NUMBER;
-          prop.p_vu.p_number = strtod(p, NULL);
-          break;
-        case 'Z':
-          prop.p_type = AMF_NULL;
-          break;
-        case 'O':
-          i = atoi(p);
-          if (i)
-            {
-              prop.p_type = AMF_OBJECT;
-            }
-          else
-            {
-              (*depth)--;
-              return 0;
-            }
-          break;
-        default:
-          return -1;
-        }
-    }
-  else if (arg[2] == ':' && arg[0] == 'N')
-    {
-      p = strchr(arg+3, ':');
-      if (!p || !*depth)
-        return -1;
-      prop.p_name.av_val = (char *)arg+3;
-      prop.p_name.av_len = p - (arg+3);
-
-      p++;
-      switch(arg[1])
-        {
-        case 'B':
-          prop.p_type = AMF_BOOLEAN;
-          prop.p_vu.p_number = atoi(p);
-          break;
-        case 'S':
-          prop.p_type = AMF_STRING;
-          STR2AVAL(prop.p_vu.p_aval,p);
-          break;
-        case 'N':
-          prop.p_type = AMF_NUMBER;
-          prop.p_vu.p_number = strtod(p, NULL);
-          break;
-        case 'O':
-          prop.p_type = AMF_OBJECT;
-          break;
-        default:
-          return -1;
-        }
-    }
-  else
-    return -1;
-
-  if (*depth)
-    {
-      AMFObject *o2;
-      for (i=0; i<*depth; i++)
-        {
-          o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
-          obj = o2;
-        }
-    }
-  AMF_AddProp(obj, &prop);
-  if (prop.p_type == AMF_OBJECT)
-    (*depth)++;
-  return 0;
+         RTMP_LogPrintf
+           ("\n%s: This program dumps the media content streamed over RTMP.\n\n", prog);
+         RTMP_LogPrintf("--help|-h               Prints this help screen.\n");
+         RTMP_LogPrintf
+           ("--rtmp|-r url           URL (e.g. rtmp://host[:port]/path)\n");
+         RTMP_LogPrintf
+           ("--host|-n hostname      Overrides the hostname in the rtmp url\n");
+         RTMP_LogPrintf
+           ("--port|-c port          Overrides the port in the rtmp url\n");
+         RTMP_LogPrintf
+           ("--socks|-S host:port    Use the specified SOCKS proxy\n");
+         RTMP_LogPrintf
+           ("--protocol|-l           Overrides the protocol in the rtmp url (0 - RTMP, 2 - RTMPE)\n");
+         RTMP_LogPrintf
+           ("--playpath|-y           Overrides the playpath parsed from rtmp url\n");
+         RTMP_LogPrintf("--swfUrl|-s url         URL to player swf file\n");
+         RTMP_LogPrintf
+           ("--tcUrl|-t url          URL to played stream (default: \"rtmp://host[:port]/app\")\n");
+         RTMP_LogPrintf("--pageUrl|-p url        Web URL of played programme\n");
+         RTMP_LogPrintf("--app|-a app            Name of target app on server\n");
+#ifdef CRYPTO
+         RTMP_LogPrintf
+           ("--swfhash|-w hexstring  SHA256 hash of the decompressed SWF file (32 bytes)\n");
+         RTMP_LogPrintf
+           ("--swfsize|-x num        Size of the decompressed SWF file, required for SWFVerification\n");
+         RTMP_LogPrintf
+           ("--swfVfy|-W url         URL to player swf file, compute hash/size automatically\n");
+         RTMP_LogPrintf
+           ("--swfAge|-X days        Number of days to use cached SWF hash before refreshing\n");
+#endif
+         RTMP_LogPrintf
+           ("--auth|-u string        Authentication string to be appended to the connect string\n");
+         RTMP_LogPrintf
+           ("--conn|-C type:data     Arbitrary AMF data to be appended to the connect string\n");
+         RTMP_LogPrintf
+           ("                        B:boolean(0|1), S:string, N:number, O:object-flag(0|1),\n");
+         RTMP_LogPrintf
+           ("                        Z:(null), NB:name:boolean, NS:name:string, NN:name:number\n");
+         RTMP_LogPrintf
+           ("--flashVer|-f string    Flash version string (default: \"%s\")\n",
+            RTMP_DefaultFlashVer.av_val);
+         RTMP_LogPrintf
+           ("--live|-v               Save a live stream, no --resume (seeking) of live streams possible\n");
+         RTMP_LogPrintf
+           ("--subscribe|-d string   Stream name to subscribe to (otherwise defaults to playpath if live is specifed)\n");
+         RTMP_LogPrintf
+           ("--flv|-o string         FLV output file name, if the file name is - print stream to stdout\n");
+         RTMP_LogPrintf
+           ("--resume|-e             Resume a partial RTMP download\n");
+         RTMP_LogPrintf
+           ("--timeout|-m num        Timeout connection num seconds (default: %lu)\n",
+            DEF_TIMEOUT);
+         RTMP_LogPrintf
+           ("--start|-A num          Start at num seconds into stream (not valid when using --live)\n");
+         RTMP_LogPrintf
+           ("--stop|-B num           Stop at num seconds into stream\n");
+         RTMP_LogPrintf
+           ("--token|-T key          Key for SecureToken response\n");
+         RTMP_LogPrintf
+           ("--hashes|-#             Display progress with hashes, not with the byte counter\n");
+         RTMP_LogPrintf
+           ("--buffer|-b             Buffer time in milliseconds (default: %lu)\n",
+            DEF_BUFTIME);
+         RTMP_LogPrintf
+           ("--skip|-k num           Skip num keyframes when looking for last keyframe to resume from. Useful if resume fails (default: %d)\n\n",
+            DEF_SKIPFRM);
+         RTMP_LogPrintf
+           ("--quiet|-q              Suppresses all command output.\n");
+         RTMP_LogPrintf("--verbose|-V            Verbose command output.\n");
+         RTMP_LogPrintf("--debug|-z              Debug level command output.\n");
+         RTMP_LogPrintf
+           ("If you don't pass parameters for swfUrl, pageUrl, or auth these properties will not be included in the connect ");
+         RTMP_LogPrintf("packet.\n\n");
 }
 
 int
@@ -720,13 +712,13 @@ main(int argc, char **argv)
   double percent = 0;
   double duration = 0.0;
 
-  int nSkipKeyFrames = 0;      // skip this number of keyframes when resuming
+  int nSkipKeyFrames = DEF_SKIPFRM;    // skip this number of keyframes when resuming
 
   bool bOverrideBufferTime = false;    // if the user specifies a buffer time override this is true
   bool bStdoutMode = true;     // if true print the stream directly to stdout, messages go to stderr
   bool bResume = false;                // true in resume mode
   uint32_t dSeek = 0;          // seek position in resume mode, 0 otherwise
-  uint32_t bufferTime = 10 * 60 * 60 * 1000;   // 10 hours as default
+  uint32_t bufferTime = DEF_BUFTIME;
 
   // meta header and initial frame for the resume mode (they are read from the file and compared with
   // the stream we are trying to continue
@@ -747,12 +739,11 @@ main(int argc, char **argv)
   bool bLiveStream = false;    // is it a live stream? then we can't seek/resume
   bool bHashes = false;                // display byte counters not hashes by default
 
-  long int timeout = 120;      // timeout connection after 120 seconds
+  long int timeout = DEF_TIMEOUT;      // timeout connection after 120 seconds
   uint32_t dStartOffset = 0;   // seek position in non-live mode
   uint32_t dStopOffset = 0;
-  uint32_t dLength = 0;                // length to play from stream - calculated from seek position and dStopOffset
+  RTMP rtmp = { 0 };
 
-  char *rtmpurl = 0;
   AVal swfUrl = { 0, 0 };
   AVal tcUrl = { 0, 0 };
   AVal pageUrl = { 0, 0 };
@@ -761,10 +752,7 @@ main(int argc, char **argv)
   AVal swfHash = { 0, 0 };
   uint32_t swfSize = 0;
   AVal flashVer = { 0, 0 };
-  AVal token = { 0, 0 };
   AVal sockshost = { 0, 0 };
-  AMFObject extras = {0};
-  int edepth = 0;
 
 #ifdef CRYPTO
   int swfAge = 30;     /* 30 days for SWF cache by default */
@@ -805,6 +793,8 @@ main(int argc, char **argv)
 
   /* sleep(30); */
 
+  RTMP_Init(&rtmp);
+
   int opt;
   struct option longopts[] = {
     {"help", 0, NULL, 'h'},
@@ -852,79 +842,7 @@ main(int argc, char **argv)
       switch (opt)
        {
        case 'h':
-         RTMP_LogPrintf
-           ("\nThis program dumps the media content streamed over RTMP.\n\n");
-         RTMP_LogPrintf("--help|-h               Prints this help screen.\n");
-         RTMP_LogPrintf
-           ("--rtmp|-r url           URL (e.g. rtmp://host[:port]/path)\n");
-         RTMP_LogPrintf
-           ("--host|-n hostname      Overrides the hostname in the rtmp url\n");
-         RTMP_LogPrintf
-           ("--port|-c port          Overrides the port in the rtmp url\n");
-         RTMP_LogPrintf
-           ("--socks|-S host:port    Use the specified SOCKS proxy\n");
-         RTMP_LogPrintf
-           ("--protocol|-l           Overrides the protocol in the rtmp url (0 - RTMP, 2 - RTMPE)\n");
-         RTMP_LogPrintf
-           ("--playpath|-y           Overrides the playpath parsed from rtmp url\n");
-         RTMP_LogPrintf("--swfUrl|-s url         URL to player swf file\n");
-         RTMP_LogPrintf
-           ("--tcUrl|-t url          URL to played stream (default: \"rtmp://host[:port]/app\")\n");
-         RTMP_LogPrintf("--pageUrl|-p url        Web URL of played programme\n");
-         RTMP_LogPrintf("--app|-a app            Name of target app on server\n");
-#ifdef CRYPTO
-         RTMP_LogPrintf
-           ("--swfhash|-w hexstring  SHA256 hash of the decompressed SWF file (32 bytes)\n");
-         RTMP_LogPrintf
-           ("--swfsize|-x num        Size of the decompressed SWF file, required for SWFVerification\n");
-         RTMP_LogPrintf
-           ("--swfVfy|-W url         URL to player swf file, compute hash/size automatically\n");
-         RTMP_LogPrintf
-           ("--swfAge|-X days        Number of days to use cached SWF hash before refreshing\n");
-#endif
-         RTMP_LogPrintf
-           ("--auth|-u string        Authentication string to be appended to the connect string\n");
-         RTMP_LogPrintf
-           ("--conn|-C type:data     Arbitrary AMF data to be appended to the connect string\n");
-         RTMP_LogPrintf
-           ("                        B:boolean(0|1), S:string, N:number, O:object-flag(0|1),\n");
-         RTMP_LogPrintf
-           ("                        Z:(null), NB:name:boolean, NS:name:string, NN:name:number\n");
-         RTMP_LogPrintf
-           ("--flashVer|-f string    Flash version string (default: \"%s\")\n",
-            RTMP_DefaultFlashVer.av_val);
-         RTMP_LogPrintf
-           ("--live|-v               Save a live stream, no --resume (seeking) of live streams possible\n");
-         RTMP_LogPrintf
-           ("--subscribe|-d string   Stream name to subscribe to (otherwise defaults to playpath if live is specifed)\n");
-         RTMP_LogPrintf
-           ("--flv|-o string         FLV output file name, if the file name is - print stream to stdout\n");
-         RTMP_LogPrintf
-           ("--resume|-e             Resume a partial RTMP download\n");
-         RTMP_LogPrintf
-           ("--timeout|-m num        Timeout connection num seconds (default: %lu)\n",
-            timeout);
-         RTMP_LogPrintf
-           ("--start|-A num          Start at num seconds into stream (not valid when using --live)\n");
-         RTMP_LogPrintf
-           ("--stop|-B num           Stop at num seconds into stream\n");
-         RTMP_LogPrintf
-           ("--token|-T key          Key for SecureToken response\n");
-         RTMP_LogPrintf
-           ("--hashes|-#             Display progress with hashes, not with the byte counter\n");
-         RTMP_LogPrintf
-           ("--buffer|-b             Buffer time in milliseconds (default: %lu), this option makes only sense in stdout mode (-o -)\n",
-            bufferTime);
-         RTMP_LogPrintf
-           ("--skip|-k num           Skip num keyframes when looking for last keyframe to resume from. Useful if resume fails (default: %d)\n\n",
-            nSkipKeyFrames);
-         RTMP_LogPrintf
-           ("--quiet|-q              Suppresses all command output.\n");
-         RTMP_LogPrintf("--verbose|-V            Verbose command output.\n");
-         RTMP_LogPrintf("--debug|-z              Debug level command output.\n");
-         RTMP_LogPrintf
-           ("If you don't pass parameters for swfUrl, pageUrl, or auth these properties will not be included in the connect ");
-         RTMP_LogPrintf("packet.\n\n");
+         usage(argv[0]);
          return RD_SUCCESS;
 #ifdef CRYPTO
        case 'w':
@@ -1014,8 +932,7 @@ main(int argc, char **argv)
          break;
        case 'l':
          protocol = atoi(optarg);
-         if (protocol != RTMP_PROTOCOL_RTMP
-             && protocol != RTMP_PROTOCOL_RTMPE)
+         if (protocol < RTMP_PROTOCOL_RTMP || protocol > RTMP_PROTOCOL_RTMPS)
            {
              RTMP_Log(RTMP_LOGERROR, "Unknown protocol specified: %d", protocol);
              return RD_FAILED;
@@ -1030,9 +947,8 @@ main(int argc, char **argv)
            unsigned int parsedPort = 0;
            int parsedProtocol = RTMP_PROTOCOL_UNDEFINED;
 
-           rtmpurl = optarg;
            if (!RTMP_ParseURL
-               (rtmpurl, &parsedProtocol, &parsedHost, &parsedPort,
+               (optarg, &parsedProtocol, &parsedHost, &parsedPort,
                 &parsedPlaypath, &parsedApp))
              {
                RTMP_Log(RTMP_LOGWARNING, "Couldn't parse the specified url (%s)!",
@@ -1084,13 +1000,16 @@ main(int argc, char **argv)
        case 'u':
          STR2AVAL(auth, optarg);
          break;
-        case 'C':
-          if (parseAMF(&extras, optarg, &edepth))
-            {
-              RTMP_Log(RTMP_LOGERROR, "Invalid AMF parameter: %s", optarg);
-              return RD_FAILED;
-            }
-          break;
+       case 'C': {
+         AVal av;
+         STR2AVAL(av, optarg);
+         if (!RTMP_SetOpt(&rtmp, &av_conn, &av))
+           {
+             RTMP_Log(RTMP_LOGERROR, "Invalid AMF parameter: %s", optarg);
+             return RD_FAILED;
+           }
+         }
+         break;
        case 'm':
          timeout = atoi(optarg);
          break;
@@ -1100,8 +1019,11 @@ main(int argc, char **argv)
        case 'B':
          dStopOffset = (int) (atof(optarg) * 1000.0);
          break;
-       case 'T':
+       case 'T': {
+         AVal token;
          STR2AVAL(token, optarg);
+         RTMP_SetOpt(&rtmp, &av_token, &token);
+         }
          break;
        case '#':
          bHashes = true;
@@ -1120,6 +1042,7 @@ main(int argc, char **argv)
          break;
        default:
          RTMP_LogPrintf("unknown option: %c\n", opt);
+         usage(argv[0]);
          return RD_FAILED;
          break;
        }
@@ -1231,18 +1154,10 @@ main(int argc, char **argv)
        }
     }
 
-  RTMP rtmp = { 0 };
-  RTMP_Init(&rtmp);
   RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
                   &tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
-                  &flashVer, &subscribepath, dSeek, 0, bLiveStream, timeout);
+                  &flashVer, &subscribepath, dSeek, dStopOffset, bLiveStream, timeout);
 
-  /* backward compatibility, we always sent this as true before */
-  if (auth.av_len)
-    rtmp.Link.authflag = true;
-
-  rtmp.Link.extras = extras;
-  rtmp.Link.token = token;
   off_t size = 0;
 
   // ok, we have to get the timestamp of the last keyframe (only keyframes are seekable) / last audio frame (audio only streams)
@@ -1339,10 +1254,8 @@ main(int argc, char **argv)
          // Calculate the length of the stream to still play
          if (dStopOffset > 0)
            {
-             dLength = dStopOffset - dSeek;
-
              // Quit if start seek is past required stop offset
-             if (dLength <= 0)
+             if (dStopOffset <= dSeek)
                {
                  RTMP_LogPrintf("Already Completed\n");
                  nStatus = RD_SUCCESS;
@@ -1350,7 +1263,7 @@ main(int argc, char **argv)
                }
            }
 
-         if (!RTMP_ConnectStream(&rtmp, dSeek, dLength))
+         if (!RTMP_ConnectStream(&rtmp, dSeek))
            {
              nStatus = RD_FAILED;
              break;
@@ -1378,15 +1291,14 @@ main(int argc, char **argv)
               dSeek = rtmp.m_pauseStamp;
               if (dStopOffset > 0)
                 {
-                  dLength = dStopOffset - dSeek;
-                  if (dLength <= 0)
+                  if (dStopOffset <= dSeek)
                     {
                       RTMP_LogPrintf("Already Completed\n");
                      nStatus = RD_SUCCESS;
                      break;
                     }
                 }
-              if (!RTMP_ReconnectStream(&rtmp, bufferTime, dSeek, dLength))
+              if (!RTMP_ReconnectStream(&rtmp, dSeek))
                 {
                  RTMP_Log(RTMP_LOGERROR, "Failed to resume the stream\n\n");
                  if (!RTMP_IsTimedout(&rtmp))
@@ -1408,7 +1320,7 @@ main(int argc, char **argv)
          bResume = true;
        }
 
-      nStatus = Download(&rtmp, file, dSeek, dLength, duration, bResume,
+      nStatus = Download(&rtmp, file, dSeek, dStopOffset, duration, bResume,
                         metaHeader, nMetaHeaderSize, initialFrame,
                         initialFrameType, nInitialFrameSize,
                         nSkipKeyFrames, bStdoutMode, bLiveStream, bHashes,
index 012c9b4..11a8477 100644 (file)
--- a/rtmpgw.c
+++ b/rtmpgw.c
@@ -343,7 +343,6 @@ void processTCPrequest(STREAMING_SERVER * server,   // server socket and state (ou
 
   RTMP rtmp = { 0 };
   uint32_t dSeek = 0;          // can be used to start from a later point in the stream
-  int32_t dLength = -1;
 
   // reset RTMP options to defaults specified upon invokation of streams
   RTMP_REQUEST req;
@@ -548,16 +547,11 @@ void processTCPrequest(STREAMING_SERVER * server, // server socket and state (ou
       RTMP_LogPrintf("Starting at TS: %d ms\n", dSeek);
     }
 
-  if (req.dStopOffset > 0)
-    {
-      dLength = req.dStopOffset - dSeek;
-    }
-
   RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", req.bufferTime);
   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, dSeek, dLength,
+                  &req.playpath, &req.tcUrl, &req.swfUrl, &req.pageUrl, &req.app, &req.auth, &req.swfHash, req.swfSize, &req.flashVer, &req.subscribepath, dSeek, req.dStopOffset,
                   req.bLiveStream, req.timeout);
   /* backward compatibility, we always sent this as true before */
   if (req.auth.av_len)
@@ -937,11 +931,11 @@ ParseOption(char opt, char *arg, RTMP_REQUEST * req)
       req->timeout = atoi(arg);
       break;
     case 'A':
-      req->dStartOffset = atoi(arg) * 1000;
+      req->dStartOffset = (int)(atof(arg) * 1000.0);
       //printf("dStartOffset = %d\n", dStartOffset);
       break;
     case 'B':
-      req->dStopOffset = atoi(arg) * 1000;
+      req->dStopOffset = (int)(atof(arg) * 1000.0);
       //printf("dStartOffset = %d\n", dStartOffset);
       break;
     case 'T':
index 066f346..dcebac0 100644 (file)
@@ -95,9 +95,6 @@ typedef struct
   Flist *f_head, *f_tail;
   Flist *f_cur;
 
-#ifdef CRYPTO
-  unsigned char hash[HASHLEN];
-#endif
 } STREAMING_SERVER;
 
 STREAMING_SERVER *rtmpServer = 0;      // server structure pointer
@@ -215,11 +212,9 @@ ServeInvoke(STREAMING_SERVER *server, int which, RTMPPacket *pack, const char *b
           else if (AVMATCH(&pname, &av_swfUrl))
             {
 #ifdef CRYPTO
-              if (pval.av_val && RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize, server->hash, 30) == 0)
-                {
-                  server->rc.Link.SWFHash.av_val = (char *)server->hash;
-                  server->rc.Link.SWFHash.av_len = HASHLEN;
-                }
+              if (pval.av_val)
+               RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize,
+                 (unsigned char *)server->rc.Link.SWFHash, 30);
 #endif
               server->rc.Link.swfUrl = pval;
               pval.av_val = NULL;
@@ -907,16 +902,16 @@ void doServe(STREAMING_SERVER * server,   // server socket and state (our listenin
                       short nType = AMF_DecodeInt16(pc.m_body);
                       /* SWFverification */
                       if (nType == 0x1a)
-  #ifdef CRYPTO
-                        if (server->rc.Link.SWFHash.av_len)
+#ifdef CRYPTO
+                        if (server->rc.Link.SWFSize)
                         {
                           RTMP_SendCtrl(&server->rc, 0x1b, 0, 0);
                           sendit = 0;
                         }
-  #else
+#else
                         /* The session will certainly fail right after this */
                         RTMP_Log(RTMP_LOGERROR, "%s, server requested SWF verification, need CRYPTO support! ", __FUNCTION__);
-  #endif
+#endif
                     }
                   else if (server->f_cur && (
                        pc.m_packetType == 0x08 ||
@@ -974,9 +969,6 @@ cleanup:
   server->rc.Link.app.av_val = NULL;
   server->rc.Link.auth.av_val = NULL;
   server->rc.Link.flashVer.av_val = NULL;
-#ifdef CRYPTO
-  server->rc.Link.SWFHash.av_val = NULL;
-#endif
   RTMP_LogPrintf("done!\n\n");
 
 quit: