Commit 8eb3ee9b authored by Reinhard Tartler's avatar Reinhard Tartler

Imported Upstream version 2.4+20111222.git4e06e218

parent 3b122c15
......@@ -4,6 +4,9 @@ Copyright 2009-2011 Howard Chu
Copyright 2009 The Flvstreamer Team
http://rtmpdump.mplayerhq.hu/
20 July 2011
- add NetStream.Authenticate.UsherToken for Justin.tv
11 July 2011, v2.4
- add RTMPE type 9 handshake support
......
......@@ -50,6 +50,7 @@ library. You can also turn it off if desired
The rtmpdump programs still link to the static library, regardless.
Note that if using OpenSSL, you must have version 0.9.8 or newer.
For Polar SSL you must have version 1.0.0 or newer.
Credit goes to team boxee for the XBMC RTMP code originally used in RTMPDumper.
The current code is based on the XBMC code but rewritten in C by Howard Chu.
......
......@@ -52,11 +52,16 @@ SODIR_mingw=$(BINDIR)
SODIR=$(SODIR_$(SYS))
SO_LDFLAGS_posix=-shared -Wl,-soname,$@
SO_LDFLAGS_darwin=-dynamiclib -flat_namespace -undefined suppress -fno-common \
-headerpad_max_install_names
SO_LDFLAGS_mingw=-shared
SO_LDFLAGS_darwin=-dynamiclib -twolevel_namespace -undefined dynamic_lookup \
-fno-common -headerpad_max_install_names -install_name $(libdir)/$@
SO_LDFLAGS_mingw=-shared -Wl,--out-implib,librtmp.dll.a
SO_LDFLAGS=$(SO_LDFLAGS_$(SYS))
INSTALL_IMPLIB_posix=
INSTALL_IMPLIB_darwin=
INSTALL_IMPLIB_mingw=cp librtmp.dll.a $(LIBDIR)
INSTALL_IMPLIB=$(INSTALL_IMPLIB_$(SYS))
SHARED=yes
SODEF_yes=-fPIC
SOLIB_yes=librtmp.$(SO_EXT)
......@@ -76,7 +81,7 @@ OBJS=rtmp.o log.o amf.o hashswf.o parseurl.o
all: librtmp.a $(SO_LIB)
clean:
rm -f *.o *.a *.$(SOX) *.$(SO_EXT)
rm -f *.o *.a *.$(SOX) *.$(SO_EXT) librtmp.pc
librtmp.a: $(OBJS)
$(AR) rs $@ $?
......@@ -100,7 +105,7 @@ librtmp.pc: librtmp.pc.in Makefile
install: install_base $(SO_INST)
install_base: librtmp.a librtmp.pc
-mkdir -p $(INCDIR) $(LIBDIR)/pkgconfig $(MANDIR)/man3
-mkdir -p $(INCDIR) $(LIBDIR)/pkgconfig $(MANDIR)/man3 $(SODIR)
cp amf.h http.h log.h rtmp.h $(INCDIR)
cp librtmp.a $(LIBDIR)
cp librtmp.pc $(LIBDIR)/pkgconfig
......@@ -108,5 +113,6 @@ install_base: librtmp.a librtmp.pc
install_so: librtmp.$(SO_EXT)
cp librtmp.$(SO_EXT) $(SODIR)
$(INSTALL_IMPLIB)
cd $(SODIR); ln -sf librtmp.$(SO_EXT) librtmp.$(SOX)
......@@ -586,7 +586,7 @@ AMF3Prop_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
case AMF3_ARRAY:
case AMF3_BYTE_ARRAY:
default:
RTMP_Log(RTMP_LOGDEBUG, "%s - AMF3 unknown/unsupported datatype 0x%02x, @0x%08X",
RTMP_Log(RTMP_LOGDEBUG, "%s - AMF3 unknown/unsupported datatype 0x%02x, @%p",
__FUNCTION__, (unsigned char)(*pBuffer), pBuffer);
return -1;
}
......@@ -735,13 +735,15 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
break;
}
case AMF_LONG_STRING:
case AMF_XML_DOC:
{
unsigned int nStringSize = AMF_DecodeInt32(pBuffer);
if (nSize < (long)nStringSize + 4)
return -1;
AMF_DecodeLongString(pBuffer, &prop->p_vu.p_aval);
nSize -= (4 + nStringSize);
prop->p_type = AMF_STRING;
if (prop->p_type == AMF_LONG_STRING)
prop->p_type = AMF_STRING;
break;
}
case AMF_RECORDSET:
......@@ -750,12 +752,6 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
return -1;
break;
}
case AMF_XML_DOC:
{
RTMP_Log(RTMP_LOGERROR, "AMF_XML_DOC not supported!");
return -1;
break;
}
case AMF_TYPED_OBJECT:
{
RTMP_Log(RTMP_LOGERROR, "AMF_TYPED_OBJECT not supported!");
......@@ -772,7 +768,7 @@ AMFProp_Decode(AMFObjectProperty *prop, const char *pBuffer, int nSize,
break;
}
default:
RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @0x%08X", __FUNCTION__,
RTMP_Log(RTMP_LOGDEBUG, "%s - unknown datatype 0x%02x, @%p", __FUNCTION__,
prop->p_type, pBuffer - 1);
return -1;
}
......@@ -1111,7 +1107,7 @@ AMF_AddProp(AMFObject *obj, const AMFObjectProperty *prop)
if (!(obj->o_num & 0x0f))
obj->o_props =
realloc(obj->o_props, (obj->o_num + 16) * sizeof(AMFObjectProperty));
obj->o_props[obj->o_num++] = *prop;
memcpy(&obj->o_props[obj->o_num++], prop, sizeof(AMFObjectProperty));
}
int
......
......@@ -30,14 +30,14 @@
#ifdef USE_POLARSSL
#include <polarssl/dhm.h>
typedef mpi * MP_t;
#define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m, NULL)
#define MP_new(m) m = malloc(sizeof(mpi)); mpi_init(m)
#define MP_set_w(mpi, w) mpi_lset(mpi, w)
#define MP_cmp(u, v) mpi_cmp_mpi(u, v)
#define MP_set(u, v) mpi_copy(u, v)
#define MP_sub_w(mpi, w) mpi_sub_int(mpi, mpi, w)
#define MP_cmp_1(mpi) mpi_cmp_int(mpi, 1)
#define MP_modexp(r, y, q, p) mpi_exp_mod(r, y, q, p, NULL)
#define MP_free(mpi) mpi_free(mpi, NULL); free(mpi)
#define MP_free(mpi) mpi_free(mpi); free(mpi)
#define MP_gethex(u, hex, res) MP_new(u); res = mpi_read_string(u, 16, hex) == 0
#define MP_bytes(u) mpi_size(u)
#define MP_setbin(u,buf,len) mpi_write_binary(u,buf,len)
......@@ -53,7 +53,7 @@ typedef struct MDH {
} MDH;
#define MDH_new() calloc(1,sizeof(MDH))
#define MDH_free(vp) {MDH *dh = vp; dhm_free(&dh->ctx); MP_free(dh->p); MP_free(dh->g); MP_free(dh->pub_key); MP_free(dh->priv_key); free(dh);}
#define MDH_free(vp) {MDH *_dh = vp; dhm_free(&_dh->ctx); MP_free(_dh->p); MP_free(_dh->g); MP_free(_dh->pub_key); MP_free(_dh->priv_key); free(_dh);}
static int MDH_generate_key(MDH *dh)
{
......@@ -71,9 +71,8 @@ static int MDH_generate_key(MDH *dh)
static int MDH_compute_key(uint8_t *secret, size_t len, MP_t pub, MDH *dh)
{
int n = len;
MP_set(&dh->ctx.GY, pub);
dhm_calc_secret(&dh->ctx, secret, &n);
dhm_calc_secret(&dh->ctx, secret, &len);
return 0;
}
......
......@@ -141,7 +141,7 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
return HTTPRES_LOST_CONNECTION;
i =
sprintf(sb.sb_buf,
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferrer: %.*s\r\n",
"GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferer: %.*s\r\n",
path, AGENT, host, (int)(path - url + 1), url);
if (http->date[0])
i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date);
......@@ -163,7 +163,7 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb)
#else
TLS_client(RTMP_TLS_ctx, sb.sb_ssl);
TLS_setfd(sb.sb_ssl, sb.sb_socket);
if ((i = TLS_connect(sb.sb_ssl)) < 0)
if (TLS_connect(sb.sb_ssl) < 0)
{
RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
ret = HTTPRES_LOST_CONNECTION;
......
.TH LIBRTMP 3 "2010-07-03" "RTMPDump v2.3"
.\" Copyright 2010 Howard Chu.
.TH LIBRTMP 3 "2011-07-20" "RTMPDump v2.4"
.\" Copyright 2011 Howard Chu.
.\" Copying permitted according to the GNU General Public License V2.
.SH NAME
librtmp \- RTMPDump Real-Time Messaging Protocol API
......@@ -161,6 +161,9 @@ These options handle additional authentication requests from the server.
Key for SecureToken response, used if the server requires SecureToken
authentication.
.TP
.BI jtv= JSON
JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken
.TP
.BI swfVfy= 0|1
If the value is 1 or TRUE, the SWF player is retrieved from the
specified
......
......@@ -6,10 +6,10 @@
<tr><td>LIBRTMP(3)<td align="center"><td align="right">LIBRTMP(3)
</thead>
<tfoot>
<tr><td>RTMPDump v2.3<td align="center">2010-07-03<td align="right">LIBRTMP(3)
<tr><td>RTMPDump v2.4<td align="center">2011-07-20<td align="right">LIBRTMP(3)
</tfoot>
<tbody><tr><td colspan="3"><br><br><ul>
<!-- Copyright 2010 Howard Chu.
<!-- Copyright 2011 Howard Chu.
Copying permitted according to the GNU General Public License V2.-->
</ul>
......@@ -238,6 +238,12 @@ authentication.
</dl>
<p>
<dl compact><dt>
<b>jtv=</b><i>JSON</i>
<dd>
JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken
</dl>
<p>
<dl compact><dt>
<b>swfVfy=</b><i>0|1</i>
<dd>
If the value is 1 or TRUE, the SWF player is retrieved from the
......
......@@ -48,9 +48,15 @@ extern RTMP_LogLevel RTMP_debuglevel;
typedef void (RTMP_LogCallback)(int level, const char *fmt, va_list);
void RTMP_LogSetCallback(RTMP_LogCallback *cb);
void RTMP_LogSetOutput(FILE *file);
#ifdef __GNUC__
void RTMP_LogPrintf(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
void RTMP_LogStatus(const char *format, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
void RTMP_Log(int level, const char *format, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
#else
void RTMP_LogPrintf(const char *format, ...);
void RTMP_LogStatus(const char *format, ...);
void RTMP_Log(int level, const char *format, ...);
#endif
void RTMP_LogHex(int level, const uint8_t *data, unsigned long len);
void RTMP_LogHexString(int level, const uint8_t *data, unsigned long len);
void RTMP_LogSetLevel(RTMP_LogLevel lvl);
......
......@@ -96,6 +96,7 @@ static int SendDeleteStream(RTMP *r, double dStreamId);
static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
static int SendPlay(RTMP *r);
static int SendBytesReceived(RTMP *r);
static int SendUsherToken(RTMP *r, AVal *usherToken);
#if 0 /* unused */
static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
......@@ -184,7 +185,7 @@ void
RTMPPacket_Dump(RTMPPacket *p)
{
RTMP_Log(RTMP_LOGDEBUG,
"RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x",
"RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %u. body: 0x%02x",
p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
}
......@@ -335,6 +336,7 @@ RTMP_SetupStream(RTMP *r,
uint32_t swfSize,
AVal *flashVer,
AVal *subscribepath,
AVal *usherToken,
int dStart,
int dStop, int bLiveStream, long int timeout)
{
......@@ -355,6 +357,8 @@ RTMP_SetupStream(RTMP *r,
RTMP_Log(RTMP_LOGDEBUG, "auth : %s", auth->av_val);
if (subscribepath && subscribepath->av_val)
RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
if (usherToken && usherToken->av_val)
RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
if (flashVer && flashVer->av_val)
RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
if (dStart > 0)
......@@ -363,7 +367,7 @@ RTMP_SetupStream(RTMP *r,
RTMP_Log(RTMP_LOGDEBUG, "StopTime : %d msec", dStop);
RTMP_Log(RTMP_LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
RTMP_Log(RTMP_LOGDEBUG, "timeout : %d sec", timeout);
RTMP_Log(RTMP_LOGDEBUG, "timeout : %ld sec", timeout);
#ifdef CRYPTO
if (swfSHA256Hash != NULL && swfSize > 0)
......@@ -372,7 +376,7 @@ RTMP_SetupStream(RTMP *r,
r->Link.SWFSize = swfSize;
RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %lu", r->Link.SWFSize);
RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %u", r->Link.SWFSize);
}
else
{
......@@ -420,6 +424,8 @@ RTMP_SetupStream(RTMP *r,
r->Link.flashVer = RTMP_DefaultFlashVer;
if (subscribepath && subscribepath->av_len)
r->Link.subscribepath = *subscribepath;
if (usherToken && usherToken->av_len)
r->Link.usherToken = *usherToken;
r->Link.seekTime = dStart;
r->Link.stopTime = dStop;
if (bLiveStream)
......@@ -477,6 +483,8 @@ static struct urlopt {
"Stream is live, no seeking possible" },
{ AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
"Stream to subscribe to" },
{ AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
"Justin.tv authentication token" },
{ AVC("token"), OFF(Link.token), OPT_STR, 0,
"Key for SecureToken response" },
{ AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
......@@ -966,7 +974,7 @@ SocksNegotiate(RTMP *r)
}
else
{
RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", packet[1]);
RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", __FUNCTION__, packet[1]);
return FALSE;
}
}
......@@ -1153,14 +1161,14 @@ RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
/* flex stream send */
RTMP_Log(RTMP_LOGDEBUG,
"%s, flex stream send, size %lu bytes, not supported, ignoring",
"%s, flex stream send, size %u bytes, not supported, ignoring",
__FUNCTION__, packet->m_nBodySize);
break;
case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
/* flex shared object */
RTMP_Log(RTMP_LOGDEBUG,
"%s, flex shared object, size %lu bytes, not supported, ignoring",
"%s, flex shared object, size %u bytes, not supported, ignoring",
__FUNCTION__, packet->m_nBodySize);
break;
......@@ -1168,7 +1176,7 @@ RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
/* flex message */
{
RTMP_Log(RTMP_LOGDEBUG,
"%s, flex message, size %lu bytes, not fully supported",
"%s, flex message, size %u bytes, not fully supported",
__FUNCTION__, packet->m_nBodySize);
/*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
......@@ -1190,7 +1198,7 @@ RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
}
case RTMP_PACKET_TYPE_INFO:
/* metadata (notify) */
RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %lu bytes", __FUNCTION__,
RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
packet->m_nBodySize);
if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
bHasMediaPacket = 1;
......@@ -1203,7 +1211,7 @@ RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
case RTMP_PACKET_TYPE_INVOKE:
/* invoke */
RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %lu bytes", __FUNCTION__,
RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
packet->m_nBodySize);
/*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
......@@ -1329,8 +1337,9 @@ ReadN(RTMP *r, char *buffer, int n)
nBytes = nRead;
r->m_nBytesIn += nRead;
if (r->m_bSendCounter
&& r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW / 2)
SendBytesReceived(r);
&& r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
if (!SendBytesReceived(r))
return FALSE;
}
/*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
#ifdef _DEBUG
......@@ -1641,6 +1650,39 @@ SendFCSubscribe(RTMP *r, AVal *subscribepath)
return RTMP_SendPacket(r, &packet, TRUE);
}
/* Justin.tv specific authentication */
static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
static int
SendUsherToken(RTMP *r, AVal *usherToken)
{
RTMPPacket packet;
char pbuf[1024], *pend = pbuf + sizeof(pbuf);
char *enc;
packet.m_nChannel = 0x03; /* control channel (invoke) */
packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
packet.m_nTimeStamp = 0;
packet.m_nInfoField2 = 0;
packet.m_hasAbsTimestamp = 0;
packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
enc = packet.m_body;
enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
*enc++ = AMF_NULL;
enc = AMF_EncodeString(enc, pend, usherToken);
if (!enc)
return FALSE;
packet.m_nBodySize = enc - packet.m_body;
return RTMP_SendPacket(r, &packet, FALSE);
}
/******************************************/
SAVC(releaseStream);
static int
......@@ -2297,7 +2339,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
{
AMFObject obj;
AVal method;
int txn;
double txn;
int ret = 0, nRes;
if (body[0] != 0x02) /* make sure it is a string method name we start with */
{
......@@ -2315,7 +2357,7 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
AMF_Dump(&obj);
AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
txn = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
if (AVMATCH(&method, &av__result))
......@@ -2324,14 +2366,14 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
int i;
for (i=0; i<r->m_numCalls; i++) {
if (r->m_methodCalls[i].num == txn) {
if (r->m_methodCalls[i].num == (int)txn) {
methodInvoked = r->m_methodCalls[i].name;
AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
break;
}
}
if (!methodInvoked.av_val) {
RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %d without matching request",
RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
__FUNCTION__, txn);
goto leave;
}
......@@ -2364,6 +2406,9 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
{
/* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
if (r->Link.usherToken.av_len)
SendUsherToken(r, &r->Link.usherToken);
/* Send the FCSubscribe if live stream or if subscribepath is set */
if (r->Link.subscribepath.av_len)
SendFCSubscribe(r, &r->Link.subscribepath);
......@@ -2539,7 +2584,7 @@ RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
if (AVMATCH(&prop->p_name, name))
{
*p = *prop;
memcpy(p, prop, sizeof(*prop));
return TRUE;
}
......@@ -2565,7 +2610,7 @@ RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
if (prop->p_name.av_len > name->av_len &&
!memcmp(prop->p_name.av_val, name->av_val, name->av_len))
{
*p = *prop;
memcpy(p, prop, sizeof(*prop));
return TRUE;
}
......@@ -3010,7 +3055,7 @@ RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
{
RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %lu",
RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %u",
__FUNCTION__, packet->m_nBodySize);
return FALSE;
}
......@@ -3581,7 +3626,9 @@ RTMPSockBuf_Close(RTMPSockBuf *sb)
sb->sb_ssl = NULL;
}
#endif
return closesocket(sb->sb_socket);
if (sb->sb_socket != -1)
return closesocket(sb->sb_socket);
return 0;
}
#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
......@@ -4129,7 +4176,7 @@ Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
if (pos + 11 + dataSize > nPacketLen)
{
RTMP_Log(RTMP_LOGERROR,
"Wrong data size (%lu), stream corrupted, aborting!",
"Wrong data size (%u), stream corrupted, aborting!",
dataSize);
ret = RTMP_READ_ERROR;
break;
......
......@@ -155,6 +155,7 @@ extern "C"
AVal auth;
AVal flashVer;
AVal subscribepath;
AVal usherToken;
AVal token;
AMFObject extras;
int edepth;
......@@ -297,6 +298,7 @@ extern "C"
uint32_t swfSize,
AVal *flashVer,
AVal *subscribepath,
AVal *usherToken,
int dStart,
int dStop, int bLiveStream, long int timeout);
......
......@@ -46,10 +46,10 @@
#include <sys/socket.h>
#include <sys/times.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#define GetSockError() errno
#define SetSockError(e) errno = e
#undef closesocket
......@@ -71,7 +71,8 @@ typedef struct tls_ctx {
#define TLS_CTX tls_ctx *
#define TLS_client(ctx,s) s = malloc(sizeof(ssl_context)); ssl_init(s);\
ssl_set_endpoint(s, SSL_IS_CLIENT); ssl_set_authmode(s, SSL_VERIFY_NONE);\
ssl_set_rng(s, havege_rand, &ctx->hs); ssl_set_ciphers(s, ssl_default_ciphers);\
ssl_set_rng(s, havege_rand, &ctx->hs);\
ssl_set_ciphersuites(s, ssl_default_ciphersuites);\
ssl_set_session(s, 1, 600, &ctx->ssn)
#define TLS_setfd(s,fd) ssl_set_bio(s, net_recv, &fd, net_send, &fd)
#define TLS_connect(s) ssl_handshake(s)
......
.TH RTMPDUMP 1 "2010-05-02" "RTMPDump v2.2e"
.\" Copyright 2010 Howard Chu.
.TH RTMPDUMP 1 "2011-07-20" "RTMPDump v2.4"
.\" Copyright 2011 Howard Chu.
.\" Copying permitted according to the GNU General Public License V2.
.SH NAME
rtmpdump \- RTMP streaming media client
......@@ -51,6 +51,8 @@ rtmpdump \- RTMP streaming media client
[\c
.BI \-T \ key\fR]
[\c
.BI \-j \ JSON\fR]
[\c
.BI \-w \ swfHash\fR]
[\c
.BI \-x \ swfSize\fR]
......@@ -210,6 +212,9 @@ These options handle additional authentication requests from the server.
Key for SecureToken response, used if the server requires SecureToken
authentication.
.TP
\fB\-\-jtv \-j\fP\ \fIJSON\fP
JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken
.TP
\fB\-\-swfhash \-w\fP\ \fIhexstring\fP
SHA256 hash of the decompressed SWF file. This option may be needed if
the server uses SWF Verification, but see the
......
......@@ -6,10 +6,10 @@
<tr><td>RTMPDUMP(1)<td align="center"><td align="right">RTMPDUMP(1)
</thead>
<tfoot>
<tr><td>RTMPDump v2.2e<td align="center">2010-05-02<td align="right">RTMPDUMP(1)
<tr><td>RTMPDump v2.4<td align="center">2011-07-20<td align="right">RTMPDUMP(1)
</tfoot>
<tbody><tr><td colspan="3"><br><br><ul>
<!-- Copyright 2010 Howard Chu.
<!-- Copyright 2011 Howard Chu.
Copying permitted according to the GNU General Public License V2.-->
</ul>
......@@ -42,6 +42,7 @@ rtmpdump &minus; RTMP streaming media client
[<b>&minus;b</b><i>&nbsp;buffer</i>]
[<b>&minus;m</b><i>&nbsp;timeout</i>]
[<b>&minus;T</b><i>&nbsp;key</i>]
[<b>&minus;j</b><i>&nbsp;JSON</i>]
[<b>&minus;w</b><i>&nbsp;swfHash</i>]
[<b>&minus;x</b><i>&nbsp;swfSize</i>]
[<b>&minus;W</b><i>&nbsp;swfUrl</i>]
......@@ -275,6 +276,12 @@ authentication.
</dl>
<p>
<dl compact><dt>
<b>&minus;&minus;jtv &minus;j</b>&nbsp;<i>JSON</i>
<dd>
JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken
</dl>
<p>
<dl compact><dt>
<b>&minus;&minus;swfhash &minus;w</b>&nbsp;<i>hexstring</i>
<dd>
SHA256 hash of the decompressed SWF file. This option may be needed if
......
......@@ -46,6 +46,7 @@
#define RD_SUCCESS 0
#define RD_FAILED 1
#define RD_INCOMPLETE 2
#define RD_NO_CONNECT 3
#define DEF_TIMEOUT 30 /* seconds */
#define DEF_BUFTIME (10 * 60 * 60 * 1000) /* 10 hours default */
......@@ -444,7 +445,7 @@ Download(RTMP * rtmp, // connected RTMP object
{
int32_t now, lastUpdate;
int bufferSize = 64 * 1024;
char *buffer = (char *) malloc(bufferSize);
char *buffer;
int nRead = 0;
off_t size = ftello(file);
unsigned long lastPercent = 0;
......@@ -505,6 +506,8 @@ Download(RTMP * rtmp, // connected RTMP object
rtmp->m_read.nMetaHeaderSize = nMetaHeaderSize;
rtmp->m_read.nInitialFrameSize = nInitialFrameSize;
buffer = (char *) malloc(bufferSize);
now = RTMP_GetTime();
lastUpdate = now - 1000;
do
......@@ -683,7 +686,7 @@ void usage(char *prog)
RTMP_LogPrintf
("--resume|-e Resume a partial RTMP download\n");
RTMP_LogPrintf
("--timeout|-m num Timeout connection num seconds (default: %lu)\n",
("--timeout|-m num Timeout connection num seconds (default: %u)\n",
DEF_TIMEOUT);
RTMP_LogPrintf
("--start|-A num Start at num seconds into stream (not valid when using --live)\n");
......@@ -691,10 +694,12 @@ void usage(char *prog)
("--stop|-B num Stop at num seconds into stream\n");
RTMP_LogPrintf
("--token|-T key Key for SecureToken response\n");
RTMP_LogPrintf
("--jtv|-j JSON Authentication token for Justin.tv legacy servers\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",
("--buffer|-b Buffer time in milliseconds (default: %u)\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",
......@@ -738,6 +743,7 @@ main(int argc, char **argv)
AVal hostname = { 0, 0 };
AVal playpath = { 0, 0 };
AVal subscribepath = { 0, 0 };
AVal usherToken = { 0, 0 }; //Justin.tv auth token
int port = -1;
int protocol = RTMP_PROTOCOL_UNDEFINED;
int retries = 0;
......@@ -839,12 +845,13 @@ main(int argc, char **argv)
{"debug", 0, NULL, 'z'},
{"quiet", 0, NULL, 'q'},
{"verbose", 0, NULL, 'V'},
{"jtv", 1, NULL, 'j'},
{0, 0, 0, 0}
};
while ((opt =
getopt_long(argc, argv,
"hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#",
"hVveqzr:s:t:p:a:b:f:o:u:C:n:c:l:y:Ym:k:d:A:B:T:w:x:W:X:S:#j:",
longopts, NULL)) != -1)
{
switch (opt)
......@@ -1051,6 +1058,9 @@ main(int argc, char **argv)
case 'S':
STR2AVAL(sockshost, optarg);
break;
case 'j':
STR2AVAL(usherToken, optarg);
break;
default:
RTMP_LogPrintf("unknown option: %c\n", opt);
usage(argv[0]);
......@@ -1142,13 +1152,14 @@ main(int argc, char **argv)
if (tcUrl.av_len == 0)
{
char str[512] = { 0 };
tcUrl.av_len = snprintf(str, 511, "%s://%.*s:%d/%.*s",
tcUrl.av_len = strlen(RTMPProtocolStringsLower[protocol]) +
hostname.av_len + app.av_len + sizeof("://:65535/");
tcUrl.av_val = (char *) malloc(tcUrl.av_len);
if (!tcUrl.av_val)
return RD_FAILED;
tcUrl.av_len = snprintf(tcUrl.av_val, tcUrl.av_len, "%s://%.*s:%d/%.*s",
RTMPProtocolStringsLower[protocol], hostname.av_len,
hostname.av_val, port, app.av_len, app.av_val);
tcUrl.av_val = (char *) malloc(tcUrl.av_len + 1);
strcpy(tcUrl.av_val, str);
}
int first = 1;
......@@ -1167,7 +1178,7 @@ main(int argc, char **argv)
RTMP_SetupStream(&rtmp, protocol, &hostname, port, &sockshost, &playpath,
&tcUrl, &swfUrl, &pageUrl, &app, &auth, &swfHash, swfSize,
&flashVer, &subscribepath, dSeek, dStopOffset, bLiveStream, timeout);
&flashVer, &subscribepath, &usherToken, dSeek, dStopOffset, bLiveStream, timeout);
/* Try to keep the stream moving if it pauses on us */
if (!bLiveStream && !(protocol & RTMP_FEATURE_HTTP))
......@@ -1244,7 +1255,7 @@ main(int argc, char **argv)
if (!RTMP_Connect(&rtmp, NULL))
{
nStatus = RD_FAILED;
nStatus = RD_NO_CONNECT;
break;
}
......
.TH RTMPGW 8 "2010-05-02" "RTMPDump v2.2e"
.\" Copyright 2010 Howard Chu.
.TH RTMPGW 8 "2011-07-20" "RTMPDump v2.4"
.\" Copyright 2011 Howard Chu.
.\" Copying permitted according to the GNU General Public License V2.
.SH NAME
rtmpgw \- RTMP streaming media gateway
......@@ -50,6 +50,8 @@ rtmpgw \- RTMP streaming media gateway
[\c
.BI \-T \ key\fR]
[\c
.BI \-j \ JSON\fR]
[\c
.BI \-w \ swfHash\fR]
[\c
.BI \-x \ swfSize\fR]
......@@ -193,6 +195,9 @@ These options handle additional authentication requests from the server.
Key for SecureToken response, used if the server requires SecureToken
authentication.
.TP
\fB\-\-jtv \-j\fP\ \fIJSON\fP
JSON token used by legacy Justin.tv servers. Invokes NetStream.Authenticate.UsherToken
.TP
\fB\-\-swfhash \-w\fP\ \fIhexstring\fP
SHA256 hash of the decompressed SWF file. This option may be needed if
the server uses SWF Verification, but see the
......
......@@ -6,10 +6,10 @@
<tr><td>RTMPGW(8)<td align="center"><td align="right">RTMPGW(8)
</thead>
<tfoot>
<tr><td>RTMPDump v2.2e<td align="center">2010-05-02<td align="right">RTMPGW(8)
<tr><td>RTMPDump v2.4<td align="center">2011-07-20<td align="right">RTMPGW(8)
</tfoot>
<tbody><tr><td colspan="3"><br><br><ul>
<!-- Copyright 2010 Howard Chu.
<!-- Copyright 2011 Howard Chu.
Copying permitted according to the GNU General Public License V2.-->
</ul>
......@@ -41,6 +41,7 @@ rtmpgw &minus; RTMP streaming media gateway
[<b>&minus;b</b><i>&nbsp;buffer</i>]
[<b>&minus;m</b><i>&nbsp;timeout</i>]
[<b>&minus;T</b><i>&nbsp;key</i>]
[<b>&minus;j</b><i>&nbsp;JSON</i>]
[<b>&minus;w</b><i>&nbsp;swfHash</i>]
[<b>&minus;x</b><i>&nbsp;swfSize</i>]
[<b>&minus;W</b><i>&nbsp;swfUrl</i>]
......@@ -249,6 +250,12 @@ authentication.
</dl>
<p>