[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