[rtmpdump] r405 - in trunk: librtmp/Makefile librtmp/handshake.h librtmp/rtmp.c librtmp/rtmp.h rtmpdump.c rtmpgw.c rtmpsuck.c

hyc subversion at mplayerhq.hu
Sat Mar 27 06:35:05 CET 2010


Author: hyc
Date: Sat Mar 27 06:35:04 2010
New Revision: 405

Log:
Option restructuring, allow most options to be passed along
with the RTMP URL, clean up

Modified:
   trunk/librtmp/Makefile
   trunk/librtmp/handshake.h
   trunk/librtmp/rtmp.c
   trunk/librtmp/rtmp.h
   trunk/rtmpdump.c
   trunk/rtmpgw.c
   trunk/rtmpsuck.c

Modified: trunk/librtmp/Makefile
==============================================================================
--- trunk/librtmp/Makefile	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/librtmp/Makefile	Sat Mar 27 06:35:04 2010	(r405)
@@ -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);" \

Modified: trunk/librtmp/handshake.h
==============================================================================
--- trunk/librtmp/handshake.h	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/librtmp/handshake.h	Sat Mar 27 06:35:04 2010	(r405)
@@ -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]);
 	}

Modified: trunk/librtmp/rtmp.c
==============================================================================
--- trunk/librtmp/rtmp.c	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/librtmp/rtmp.c	Sat Mar 27 06:35:04 2010	(r405)
@@ -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 seekT
 }
 
 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 *pa
       //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)
     {

Modified: trunk/librtmp/rtmp.h
==============================================================================
--- trunk/librtmp/rtmp.h	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/librtmp/rtmp.h	Sat Mar 27 06:35:04 2010	(r405)
@@ -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);

Modified: trunk/rtmpdump.c
==============================================================================
--- trunk/rtmpdump.c	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/rtmpdump.c	Sat Mar 27 06:35:04 2010	(r405)
@@ -46,6 +46,10 @@
 #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 f
 
 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
 	}
     }
 
-  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
 
 #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);
-
-  /* backward compatibility, we always sent this as true before */
-  if (auth.av_len)
-    rtmp.Link.authflag = true;
+		   &flashVer, &subscribepath, dSeek, dStopOffset, bLiveStream, timeout);
 
-  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,

Modified: trunk/rtmpgw.c
==============================================================================
--- trunk/rtmpgw.c	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/rtmpgw.c	Sat Mar 27 06:35:04 2010	(r405)
@@ -343,7 +343,6 @@ void processTCPrequest(STREAMING_SERVER 
 
   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 
       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_RE
       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':

Modified: trunk/rtmpsuck.c
==============================================================================
--- trunk/rtmpsuck.c	Fri Mar 26 22:07:03 2010	(r404)
+++ trunk/rtmpsuck.c	Sat Mar 27 06:35:04 2010	(r405)
@@ -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, in
           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,	
                       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:


More information about the rtmpdump mailing list