[rtmpdump] r239 - in trunk: hashswf.c rtmp.h rtmpdump.c rtmpsuck.c streams.c

hyc subversion at mplayerhq.hu
Tue Jan 19 01:58:22 CET 2010


Author: hyc
Date: Tue Jan 19 01:58:21 2010
New Revision: 239

Log:
Add ctim to ~/.swfinfo, recording the last time we checked on the
info for a given SWF. Use Age parameter to control how often we check.

Modified:
   trunk/hashswf.c
   trunk/rtmp.h
   trunk/rtmpdump.c
   trunk/rtmpsuck.c
   trunk/streams.c

Modified: trunk/hashswf.c
==============================================================================
--- trunk/hashswf.c	Mon Jan 18 23:42:50 2010	(r238)
+++ trunk/hashswf.c	Tue Jan 19 01:58:21 2010	(r239)
@@ -20,6 +20,8 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <ctype.h>
+#include <time.h>
 
 #include "rtmp.h"
 
@@ -234,14 +236,98 @@ leave:
   return ret;
 }
 
+static const char *monthtab[12] = {"Jan", "Feb", "Mar",
+				"Apr", "May", "Jun",
+				"Jul", "Aug", "Sep",
+				"Oct", "Nov", "Dec"};
+static const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+/* Parse an HTTP datestamp into Unix time */
+static time_t
+make_unix_time(char *s)
+{
+    struct tm       time;
+    int             i, ysub = 1900, fmt = 0;
+    char           *month;
+    char           *n;
+    time_t res;
+
+    if (s[3] != ' ')
+    {
+	fmt = 1;
+	if (s[3] != ',')
+	    ysub = 0;
+    }
+    for (n = s; *n; ++n)
+	if (*n == '-' || *n == ':')
+	    *n = ' ';
+
+    time.tm_mon = 0;
+    n = strchr(s, ' ');
+    if (fmt)
+    {
+	/* Day, DD-MMM-YYYY HH:MM:SS GMT */
+	time.tm_mday = strtol(n+1, &n, 0);
+	month = n+1;
+	n = strchr(month, ' ');
+	time.tm_year = strtol(n+1, &n, 0);
+	time.tm_hour = strtol(n+1, &n, 0);
+	time.tm_min = strtol(n+1, &n, 0);
+	time.tm_sec = strtol(n+1, NULL, 0);
+    } else
+    {
+	/* Unix ctime() format. Does not conform to HTTP spec. */
+	/* Day MMM DD HH:MM:SS YYYY */
+	month = n+1;
+	n = strchr(month, ' ');
+	while (isspace(*n)) n++;
+	time.tm_mday = strtol(n, &n, 0);
+	time.tm_hour = strtol(n+1, &n, 0);
+	time.tm_min = strtol(n+1, &n, 0);
+	time.tm_sec = strtol(n+1, &n, 0);
+	time.tm_year = strtol(n+1, NULL, 0);
+    }
+    if (time.tm_year > 100)
+	time.tm_year -= ysub;
+
+    for (i = 0; i < 12; i++)
+	if (!strncasecmp(month, monthtab[i], 3))
+	{
+	    time.tm_mon = i;
+	    break;
+	}
+    time.tm_isdst = 0;		/* daylight saving is never in effect in GMT */
+    res = mktime(&time);
+    /* Unfortunately, mktime() assumes the input is in local time,
+     * not GMT, so we have to correct it here.
+     */
+    if (res != -1)
+	res += timezone;
+    return res;
+}
+
+/* Convert a Unix time to a network time string
+ * Weekday, DD-MMM-YYYY HH:MM:SS GMT
+ */
+void strtime(time_t *t, char *s)
+{
+    struct tm *tm;
+
+    tm = gmtime((time_t *)t);
+    sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT",
+	days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon],
+	tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
 #define HEX2BIN(a)      (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
 
 int
-RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int ask)
+RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age)
 {
   FILE *f = NULL;
-  char *path, *home, date[64];
+  char *path, *home, date[64], cctim[64];
   long pos = 0;
+  time_t ctim = 0, cnow;
   int i, got = 0, ret = 0;
   unsigned int hlen;
   struct info in = {0};
@@ -253,6 +339,16 @@ RTMP_HashSWF(const char *url, unsigned i
   if (!home)
     home = ".";
 
+  /* SWF hash info is cached in a fixed-format file.
+   * url: <url of SWF file>
+   * ctim: HTTP datestamp of when we last checked it.
+   * date: HTTP datestamp of the SWF's last modification.
+   * size: SWF size in hex
+   * hash: SWF hash in hex
+   *
+   * These fields must be present in this order. All fields
+   * besides URL are fixed size.
+   */
   path=malloc(strlen(home)+sizeof("/.swfinfo"));
   strcpy(path, home);
   strcat(path, "/.swfinfo");
@@ -314,6 +410,12 @@ RTMP_HashSWF(const char *url, unsigned i
                   strncpy(date, buf+6, sizeof(date));
                   got++;
                 }
+              else if (!strncmp(buf, "ctim: ", 6))
+                {
+                  buf[strlen(buf)-1] = '\0';
+		  ctim = make_unix_time(buf+6);
+                  got++;
+                }
               else if (!strncmp(buf, "url: ", 5))
                 break;
             }
@@ -322,8 +424,15 @@ RTMP_HashSWF(const char *url, unsigned i
       break;
     }
 
-  if (got && !ask)
-    goto out;
+  cnow = time(NULL);
+  /* If we got a cache time, see if it's young enough to use directly */
+  if (got && ctim)
+    {
+      ctim = cnow - ctim;
+      ctim /= 3600 * 24; /* seconds to days */
+      if (ctim < age)	/* ok, it's new enough */
+        goto out;
+    }
 
   in.first = 1;
   in.date = date;
@@ -342,11 +451,8 @@ RTMP_HashSWF(const char *url, unsigned i
       Log(LOGERROR, "%s: couldn't contact swfurl %s",
         __FUNCTION__, url);
     }
-  else if (!in.first)
+  else
     {
-      HMAC_Final(&ctx, (unsigned char *)hash, &hlen);
-      *size = in.size;
-
       if (got && pos)
         fseek(f, pos, SEEK_SET);
       else
@@ -371,12 +477,21 @@ RTMP_HashSWF(const char *url, unsigned i
 
           fprintf(f, "url: %.*s\n", i, url);
         }
-      fprintf(f, "date: %s\n", date);
-      fprintf(f, "size: %08x\n", in.size);
-      fprintf(f, "hash: ");
-      for (i=0; i<SHA256_DIGEST_LENGTH; i++)
-        fprintf(f, "%02x", hash[i]);
-      fprintf(f, "\n");
+      strtime(&cnow, cctim);
+      fprintf(f, "ctim: %s\n", cctim);
+
+      if (!in.first)
+        {
+          HMAC_Final(&ctx, (unsigned char *)hash, &hlen);
+          *size = in.size;
+
+          fprintf(f, "date: %s\n", date);
+          fprintf(f, "size: %08x\n", in.size);
+          fprintf(f, "hash: ");
+          for (i=0; i<SHA256_DIGEST_LENGTH; i++)
+            fprintf(f, "%02x", hash[i]);
+          fprintf(f, "\n");
+        }
     }
   HMAC_CTX_cleanup(&ctx);
 out:

Modified: trunk/rtmp.h
==============================================================================
--- trunk/rtmp.h	Mon Jan 18 23:42:50 2010	(r238)
+++ trunk/rtmp.h	Tue Jan 19 01:58:21 2010	(r239)
@@ -252,7 +252,7 @@ bool RTMPSockBuf_Fill(RTMPSockBuf *sb);
 /* hashswf.c */
 #define HASHLEN	32
 
-int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int ask);
+int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age);
 #endif
 
 #endif

Modified: trunk/rtmpdump.c
==============================================================================
--- trunk/rtmpdump.c	Mon Jan 18 23:42:50 2010	(r238)
+++ trunk/rtmpdump.c	Tue Jan 19 01:58:21 2010	(r239)
@@ -1197,6 +1197,8 @@ main(int argc, char **argv)
   int edepth = 0;
 
 #ifdef CRYPTO
+  int swfAge = 30;	/* 30 days for SWF cache by default */
+  int swfVfy = 0;
   unsigned char hash[HASHLEN];
 #endif
 
@@ -1261,6 +1263,7 @@ main(int argc, char **argv)
     {"swfhash", 1, NULL, 'w'},
     {"swfsize", 1, NULL, 'x'},
     {"swfVfy", 1, NULL, 'W'},
+    {"swfAge", 1, NULL, 'X'},
 #endif
     {"flashVer", 1, NULL, 'f'},
     {"live", 0, NULL, 'v'},
@@ -1282,7 +1285,7 @@ main(int argc, char **argv)
 
   while ((opt =
 	  getopt_long(argc, argv,
-		      "hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:m:k:d:A:B:T:w:x:W:S:#",
+		      "hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:m:k:d:A:B:T:w:x:W:X:S:#",
 		      longopts, NULL)) != -1)
     {
       switch (opt)
@@ -1315,6 +1318,8 @@ main(int argc, char **argv)
 	    ("--swfsize|-x num        Size of the decompressed SWF file, required for SWFVerification\n");
 	  LogPrintf
 	    ("--swfVfy|-W url         URL to player swf file, compute hash/size automatically\n");
+	  LogPrintf
+	    ("--swfAge|-X days        Number of days to use cached SWF hash before refreshing\n");
 #endif
 	  LogPrintf
 	    ("--auth|-u string        Authentication string to be appended to the connect string\n");
@@ -1388,11 +1393,20 @@ main(int argc, char **argv)
 	  }
         case 'W':
 	  STR2AVAL(swfUrl, optarg);
-          if (RTMP_HashSWF(optarg, &swfSize, hash, 1) == 0)
-            {
-              swfHash.av_val = (char *)hash;
-              swfHash.av_len = HASHLEN;
-            }
+	  swfVfy = 1;
+          break;
+        case 'X':
+	  {
+	    int num = atoi(optarg);
+	    if (num < 1)
+	      {
+		Log(LOGERROR, "SWF Age must be at least 1, ignoring\n");
+	      }
+	    else
+	      {
+		swfAge = num;
+	      }
+	  }
           break;
 #endif
 	case 'k':
@@ -1601,6 +1615,16 @@ main(int argc, char **argv)
       bResume = false;
     }
 
+#ifdef CRYPTO
+  if (swfVfy)
+    {
+      if (RTMP_HashSWF(swfUrl.av_val, &swfSize, hash, swfAge) == 0)
+        {
+          swfHash.av_val = (char *)hash;
+          swfHash.av_len = HASHLEN;
+        }
+    }
+
   if (swfHash.av_len == 0 && swfSize > 0)
     {
       Log(LOGWARNING,
@@ -1615,6 +1639,7 @@ main(int argc, char **argv)
       swfHash.av_len = 0;
       swfHash.av_val = NULL;
     }
+#endif
 
   if (flashVer.av_len == 0)
     {

Modified: trunk/rtmpsuck.c
==============================================================================
--- trunk/rtmpsuck.c	Mon Jan 18 23:42:50 2010	(r238)
+++ trunk/rtmpsuck.c	Tue Jan 19 01:58:21 2010	(r239)
@@ -95,6 +95,9 @@ 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
@@ -212,11 +215,9 @@ ServeInvoke(STREAMING_SERVER *server, in
           else if (AVMATCH(&pname, &av_swfUrl))
             {
 #ifdef CRYPTO
-              unsigned char hash[HASHLEN];
-              if (RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize, hash, 0) == 0)
+              if (RTMP_HashSWF(pval.av_val, &server->rc.Link.SWFSize, server->hash, 30) == 0)
                 {
-                  server->rc.Link.SWFHash.av_val = malloc(HASHLEN);
-                  memcpy(server->rc.Link.SWFHash.av_val, hash, HASHLEN);
+                  server->rc.Link.SWFHash.av_val = (char *)server->hash;
                   server->rc.Link.SWFHash.av_len = HASHLEN;
                 }
 #endif
@@ -968,7 +969,6 @@ cleanup:
   server->rc.Link.auth.av_val = NULL;
   server->rc.Link.flashVer.av_val = NULL;
 #ifdef CRYPTO
-  free(server->rc.Link.SWFHash.av_val);
   server->rc.Link.SWFHash.av_val = NULL;
 #endif
   LogPrintf("done!\n\n");

Modified: trunk/streams.c
==============================================================================
--- trunk/streams.c	Mon Jan 18 23:42:50 2010	(r238)
+++ trunk/streams.c	Tue Jan 19 01:58:21 2010	(r239)
@@ -99,10 +99,14 @@ typedef struct
   AMFObject extras;
   int edepth;
   uint32_t swfSize;
+  int swfAge;
+  int swfVfy;
 
   uint32_t dStartOffset;
   uint32_t dStopOffset;
   uint32_t nTimeStamp;
+
+  unsigned char hash[HASHLEN];
 } RTMP_REQUEST;
 
 #define STR2AVAL(av,str)	av.av_val = str; av.av_len = strlen(av.av_val)
@@ -701,6 +705,15 @@ void processTCPrequest(STREAMING_SERVER 
   if (req.rtmpport == 0)
     req.rtmpport = 1935;
 
+  if (req.swfVfy)
+    {
+        if (RTMP_HashSWF(req.swfUrl.av_val, &req.swfSize, req.hash, req.swfAge) == 0)
+          {
+            req.swfHash.av_val = (char *)req.hash;
+            req.swfHash.av_len = HASHLEN;
+          }
+    }
+
   // after validation of the http request send response header
   sprintf(buf, "HTTP/1.0 200 OK%s", srvhead);
   send(sockfd, buf, (int) strlen(buf), 0);
@@ -1000,17 +1013,23 @@ ParseOption(char opt, char *arg, RTMP_RE
       }
     case 'W':
       {
-        unsigned char hash[HASHLEN];
-
         STR2AVAL(req->swfUrl, arg);
-        if (RTMP_HashSWF(arg, &req->swfSize, hash, 1) == 0)
-          {
-            req->swfHash.av_val = malloc(HASHLEN);
-            req->swfHash.av_len = HASHLEN;
-            memcpy(req->swfHash.av_val, hash, HASHLEN);
-          }
+        req->swfVfy = 1;
       }
       break;
+    case 'X':
+      {
+	int num = atoi(arg);
+	if (num <= 0)
+	  {
+	    Log(LOGERROR, "SWF Age must be at least 1, ignoring\n");
+	  }
+	else
+	  {
+	    req->swfAge = num;
+	  }
+	break;
+      }
 #endif
     case 'b':
       {
@@ -1167,6 +1186,7 @@ main(int argc, char **argv)
   defaultRTMPRequest.timeout = 300;	// timeout connection afte 300 seconds
   defaultRTMPRequest.bufferTime = 20 * 1000;
 
+  defaultRTMPRequest.swfAge = 30;
 
   int opt;
   struct option longopts[] = {
@@ -1184,6 +1204,7 @@ main(int argc, char **argv)
     {"swfhash", 1, NULL, 'w'},
     {"swfsize", 1, NULL, 'x'},
     {"swfVfy", 1, NULL, 'W'},
+    {"swfAge", 1, NULL, 'X'},
 #endif
     {"auth", 1, NULL, 'u'},
     {"conn", 1, NULL, 'C'},
@@ -1215,7 +1236,7 @@ main(int argc, char **argv)
 
   while ((opt =
 	  getopt_long(argc, argv,
-		      "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:", longopts,
+		      "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:X:", longopts,
 		      NULL)) != -1)
     {
       switch (opt)
@@ -1246,6 +1267,8 @@ main(int argc, char **argv)
 	    ("--swfsize|-x num        Size of the decompressed SWF file, required for SWFVerification\n");
 	  LogPrintf
 	    ("--swfVfy|-W url         URL to player swf file, compute hash/size automatically\n");
+	  LogPrintf
+	    ("--swfAge|-X days        Number of days to use cached SWF hash before refreshing\n");
 #endif
 	  LogPrintf
 	    ("--auth|-u string        Authentication string to be appended to the connect string\n");


More information about the rtmpdump mailing list