[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Gnash-commit] gnash ChangeLog libamf/amf.cpp libamf/amf.h lib...
From: |
Rob Savoye |
Subject: |
[Gnash-commit] gnash ChangeLog libamf/amf.cpp libamf/amf.h lib... |
Date: |
Fri, 16 May 2008 03:46:40 +0000 |
CVSROOT: /sources/gnash
Module name: gnash
Changes by: Rob Savoye <rsavoye> 08/05/16 03:46:39
Modified files:
. : ChangeLog
libamf : amf.cpp amf.h buffer.cpp buffer.h element.cpp
element.h sol.cpp sol.h
libnet : Makefile.am handler.cpp http.cpp rtmp.cpp
rtmp.h rtmp_server.cpp rtmp_server.h
testsuite/libamf.all: test_sol.cpp
testsuite/libnet.all: test_cque.cpp test_handler.cpp
test_rtmp.cpp
Added files:
libnet : rtmp_client.cpp rtmp_client.h rtmp_msg.cpp
rtmp_msg.h
Log message:
* libamf/amf.cpp: Trap the new AMF3 type. Decode objects
correctly.
* libamf.buffer.{h,cpp}: Resize to hold the data up to the
current
seek pointer if no argument.
* libamf/element.cpp: Trap the switch from AMF0 to AMF3. Dump
properties too.
* libamf/sol.cpp: Properties in a SOL file have a zero byte
terminator after each one.
* libnet/Makefile.am: Add new files, rtmp_msg.* and
rtmp_client.*.
* libnet/rtmp_client.{g,cpp}: Client side support for RTMP.
* libnet/rtmp_msg.{g,cpp}: Represent an RTMP packet, inckuding
the
header.
* libnet/http.cpp: Cleanup warnings.
* libnet/rtmp.cpp: Move client side methods to new RTMPClient
class and other to RTMPMsg. Decode result messages from media
server. Cleanup warnings.
* libnet/rtmp_server.cpp: Build result messages for client.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.6610&r2=1.6611
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/amf.cpp?cvsroot=gnash&r1=1.78&r2=1.79
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/amf.h?cvsroot=gnash&r1=1.42&r2=1.43
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/buffer.cpp?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/buffer.h?cvsroot=gnash&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/element.cpp?cvsroot=gnash&r1=1.25&r2=1.26
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/element.h?cvsroot=gnash&r1=1.21&r2=1.22
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/sol.cpp?cvsroot=gnash&r1=1.36&r2=1.37
http://cvs.savannah.gnu.org/viewcvs/gnash/libamf/sol.h?cvsroot=gnash&r1=1.13&r2=1.14
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/Makefile.am?cvsroot=gnash&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/handler.cpp?cvsroot=gnash&r1=1.6&r2=1.7
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/http.cpp?cvsroot=gnash&r1=1.9&r2=1.10
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp.cpp?cvsroot=gnash&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp.h?cvsroot=gnash&r1=1.8&r2=1.9
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_server.cpp?cvsroot=gnash&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_server.h?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_client.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_client.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_msg.cpp?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/libnet/rtmp_msg.h?cvsroot=gnash&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/libamf.all/test_sol.cpp?cvsroot=gnash&r1=1.13&r2=1.14
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/libnet.all/test_cque.cpp?cvsroot=gnash&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/libnet.all/test_handler.cpp?cvsroot=gnash&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/libnet.all/test_rtmp.cpp?cvsroot=gnash&r1=1.1&r2=1.2
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.6610
retrieving revision 1.6611
diff -u -b -r1.6610 -r1.6611
--- ChangeLog 15 May 2008 14:41:09 -0000 1.6610
+++ ChangeLog 16 May 2008 03:46:11 -0000 1.6611
@@ -1,3 +1,23 @@
+2008-05-15 Rob Savoye <address@hidden>
+
+ * libamf/amf.cpp: Trap the new AMF3 type. Decode objects
+ correctly.
+ * libamf.buffer.{h,cpp}: Resize to hold the data up to the current
+ seek pointer if no argument.
+ * libamf/element.cpp: Trap the switch from AMF0 to AMF3. Dump
+ properties too.
+ * libamf/sol.cpp: Properties in a SOL file have a zero byte
+ terminator after each one.
+ * libnet/Makefile.am: Add new files, rtmp_msg.* and rtmp_client.*.
+ * libnet/rtmp_client.{g,cpp}: Client side support for RTMP.
+ * libnet/rtmp_msg.{g,cpp}: Represent an RTMP packet, inckuding the
+ header.
+ * libnet/http.cpp: Cleanup warnings.
+ * libnet/rtmp.cpp: Move client side methods to new RTMPClient
+ class and other to RTMPMsg. Decode result messages from media
+ server. Cleanup warnings.
+ * libnet/rtmp_server.cpp: Build result messages for client.
+
2008-05-15 Sandro Santilli <address@hidden>
* server/parser/movie_def_impl.cpp (readHeader): limit FPS to a max of
Index: libamf/amf.cpp
===================================================================
RCS file: /sources/gnash/gnash/libamf/amf.cpp,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -b -r1.78 -r1.79
--- libamf/amf.cpp 7 May 2008 20:59:29 -0000 1.78
+++ libamf/amf.cpp 16 May 2008 03:46:17 -0000 1.79
@@ -70,7 +70,8 @@
"Unsupported",
"Recordset",
"XMLObject",
- "TypedObject"
+ "TypedObject",
+ "AMF3 Data"
};
AMF::AMF()
@@ -196,7 +197,7 @@
Buffer *
AMF::encodeBoolean(bool flag)
{
- GNASH_REPORT_FUNCTION;
+// GNASH_REPORT_FUNCTION;
// Encode a boolean value. 0 for false, 1 for true
Buffer *buf = new Buffer(2);
buf->append(Element::BOOLEAN_AMF0);
@@ -442,7 +443,7 @@
Buffer *
AMF::encodeString(Network::byte_t *data, size_t size)
{
- GNASH_REPORT_FUNCTION;
+// GNASH_REPORT_FUNCTION;
boost::uint16_t length;
Buffer *buf = new Buffer(size + AMF_HEADER_SIZE);
@@ -503,9 +504,9 @@
Buffer *
AMF::encodeElement(Element *el)
{
- GNASH_REPORT_FUNCTION;
+// GNASH_REPORT_FUNCTION;
Buffer *buf = 0;
- Buffer *tmp;
+ Buffer *tmp = 0;
size_t outsize;
if (el->getType() == Element::BOOLEAN_AMF0) {
@@ -541,7 +542,7 @@
tmp = encodeBoolean(el->to_bool());
break;
case Element::STRING_AMF0:
- tmp = encodeString(el->getData(), el->getLength()-1);
+ tmp = encodeString(el->getData(), el->getLength());
break;
case Element::OBJECT_AMF0:
tmp = el->encode();
@@ -593,6 +594,9 @@
// case Element::VARIABLE:
// case Element::FUNCTION:
// break;
+ case Element::AMF3_DATA:
+ log_error("FIXME: got AMF3 data type");
+ break;
default:
tmp = 0;
break;
@@ -669,10 +673,10 @@
Element *
AMF::extractAMF(Network::byte_t *in, Network::byte_t* tooFar)
{
-// GNASH_REPORT_FUNCTION;
+ GNASH_REPORT_FUNCTION;
Element *el = new Element;
- Network::byte_t *tmpptr;
+ Network::byte_t *tmpptr = in;
boost::uint16_t length;
if (in == 0) {
@@ -680,8 +684,6 @@
return 0;
}
- tmpptr = in;
-
// All elements look like this:
// the first two bytes is the length of name of the element
// Then the next bytes are the element name
@@ -694,62 +696,60 @@
// mostly to make valgrind shut up, as it has a tendency to
// complain about legit code when it comes to all this byte
// manipulation stuff.
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, 1);
-#endif
char c = *(reinterpret_cast<char *>(tmpptr));
Element::amf0_type_e type = static_cast<Element::amf0_type_e>(c);
- tmpptr++; // skip the header byte
+ tmpptr++; // skip past the header byte
AMF amf_obj;
switch (type) {
case Element::NUMBER_AMF0:
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, AMF0_NUMBER_SIZE);
-#endif
el->makeNumber(tmpptr);
tmpptr += AMF0_NUMBER_SIZE; // all numbers are 8 bit big endian
break;
case Element::BOOLEAN_AMF0:
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, sizeof(boost::uint16_t));
-#endif
el->makeBoolean(tmpptr);
tmpptr += sizeof(bool);
// tmpptr += sizeof(boost::uint16_t); // although a bool is one byte,
it's stored as a short
break;
case Element::STRING_AMF0:
// get the length of the name
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, sizeof(boost::uint16_t));
-#endif
length = ntohs((*(boost::uint16_t *)tmpptr) & 0xffff);
tmpptr += sizeof(boost::uint16_t);
- log_debug(_("AMF String length is: %d"), length);
+ if (length >= SANE_STR_SIZE) {
+ log_error("%d bytes for a string is over the safe limit of %d",
+ length, SANE_STR_SIZE);
+ return 0;
+ }
+// log_debug(_("AMF String length is: %d"), length);
if (length > 0) {
// get the name of the element
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, length);
-#endif
el->makeString(tmpptr, length);
- log_debug(_("AMF String is: %s"), el->to_string());
+// log_debug(_("AMF String is: %s"), el->to_string());
tmpptr += length;
} else {
el->setType(Element::STRING_AMF0);
};
break;
case Element::OBJECT_AMF0:
+ {
el->makeObject();
- Element *child;
- do {
- child = amf_obj.extractProperty(tmpptr, tooFar);
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, amf_obj.totalsize()-1);
-#endif
- tmpptr += amf_obj.totalsize() - 1;
+ while (tmpptr < (tooFar - AMF_HEADER_SIZE)) {
+ if (*tmpptr == TERMINATOR) {
+// log_debug("No data associated with Property in object");
+ tmpptr++;
+ break;
+ }
+ Element *child = amf_obj.extractProperty(tmpptr, tooFar);
+ if (child == 0) {
+ break;
+ }
+// child->dump();
el->addProperty(child);
- } while (tmpptr < tooFar && *tmpptr != Element::OBJECT_END_AMF0);
+ tmpptr += amf_obj.totalsize();
+ };
+ tmpptr += AMF_HEADER_SIZE; // skip past the terminator
bytes
break;
+ }
case Element::MOVIECLIP_AMF0:
case Element::NULL_AMF0:
case Element::UNDEFINED_AMF0:
@@ -763,13 +763,14 @@
case Element::RECORD_SET_AMF0:
case Element::XML_OBJECT_AMF0:
case Element::TYPED_OBJECT_AMF0:
+ case Element::AMF3_DATA:
default:
-// log_unimpl("%s: type %d", __PRETTY_FUNCTION__, (int)type);
+ log_unimpl("%s: type %d", __PRETTY_FUNCTION__, (int)type);
return 0;
}
// Calculate the offset for the next read
- _totalsize = (tmpptr - in) + 1;
+ _totalsize = (tmpptr - in);
return el;
}
@@ -787,142 +788,60 @@
Element *
AMF::extractProperty(Network::byte_t *in, Network::byte_t* tooFar)
{
-// GNASH_REPORT_FUNCTION;
+ GNASH_REPORT_FUNCTION;
Network::byte_t *tmpptr = in;
- boost::uint16_t length = 0;
-
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, sizeof(boost::uint16_t));
-#endif
+ boost::uint16_t length;
- length = *(reinterpret_cast<boost::uint16_t *>(tmpptr));
-// length = tmpptr[1]; // FIXME: hack. This supports
-// // strings up to 256 characters
-// // but keep svalgrind happy.
- swapBytes(&length, sizeof(boost::uint16_t));
+ length = ntohs((*(boost::uint16_t *)tmpptr) & 0xffff);
+ // go past the length bytes, which leaves us pointing at the raw data
tmpptr += sizeof(boost::uint16_t);
+ // sanity check the length of the data. The length is usually only zero if
+ // we've gone all the way to the end of the object.
+
+ // valrind comlains length is unintialized, which as we just set
+ // length to a value, this is tottaly bogus, and I'm tired of
+ // braindamaging code to keep valgrind happy.
if (length <= 0) {
-// if (*(in+2) == Element::OBJECT_END) {
- log_debug(_("End of Object definition"));
-// el->setType(Element::OBJECT_END);
-// return el;
-// }
-// delete el;
+ log_debug("No Property name, object done");
return 0;
}
-
- Element *el = new Element;
- // get the name of the element, the length of which we just decoded
- if (length > 0) {
-// log_debug(_("AMF element length is: %d"), length);
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, length);
-#endif
- el->setName(tmpptr, length);
-// log_debug(_("AMF element name is: %s"), el->getName());
- tmpptr += length;
+ if (length >= SANE_STR_SIZE) {
+ log_error("%d bytes for a string is over the safe limit of %d",
+ length, SANE_STR_SIZE);
+ return 0;
}
- // get the type of the element, which is a single byte.
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, 1);
-#endif
- char c = *(reinterpret_cast<char *>(tmpptr));
- Element::amf0_type_e type = static_cast<Element::amf0_type_e>(c);
- tmpptr++;
-
- if (type != Element::TYPED_OBJECT_AMF0) {
-// log_debug(_("AMF type is: %s"), amftype_str[(int)type]);
- el->setType(type);
- }
+ // name is just debugging help to print cleaner, and should be removed
later
+ log_debug(_("AMF property name length is: %d"), length);
+ const char *name = strndup(reinterpret_cast<const char *>(tmpptr), length);
+ log_debug(_("AMF property name is: %s"), name);
- switch (type) {
- case Element::NUMBER_AMF0:
- {
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, sizeof(double));
-#endif
- double num = *reinterpret_cast<const double*>(tmpptr);
- swapBytes(&num, AMF0_NUMBER_SIZE);
- el->makeNumber(num);
- tmpptr += AMF0_NUMBER_SIZE;
- break;
- }
- case Element::BOOLEAN_AMF0:
- {
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, 1);
-#endif
- //
- // @@strk@@ : we read 2 bytes from ::extractAMF, why only 1 here in
::extractProperty ?
- //
- bool sheet = *(reinterpret_cast<bool *>(tmpptr));
- el->makeBoolean(sheet);
- tmpptr += 1;
- break;
- }
- case Element::STRING_AMF0:
- // extractString returns a printable char *. First 2 bytes for the
length,
- // and then read the string, which is NOT NULL terminated.
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, sizeof(boost::uint16_t));
-#endif
- length = *reinterpret_cast<boost::uint16_t *>(tmpptr);
- swapBytes(&length, sizeof(boost::uint16_t));
- tmpptr += sizeof(boost::uint16_t);
- if (length > 0) {
-#ifndef GNASH_TRUST_AMF
- ENSUREBYTES(tmpptr, tooFar, length);
-#endif
- el->makeString(tmpptr, length);
+ Element *el = 0;
+ // If we get a NULL object, there is no data. In that case, we only return
+ // the name of the property.
+ if (*(tmpptr+length) == Element::NULL_AMF0) {
+ log_debug("No data associated with Property \"%s\"", name);
+ el = new Element;
+ el->setName(name, length);
+ tmpptr += length + 1;
+ // Calculate the offset for the next read
+ } else {
+ // process the data with associated with the property.
+ // Go past the data to the start of the next AMF object, which
+ // should be a type byte.
tmpptr += length;
+ el = extractAMF(tmpptr, tooFar);
+ if (el) {
+ el->setName(name, length);
+ tmpptr += totalsize();
}
- if (length == 0) {
-// log_debug("NullString");
- el->makeNullString();
- }
-// log_debug(_("Property \"%s\" is: %s"), el->getName(),
el->to_string());
- break;
- case Element::OBJECT_AMF0:
- while ( (tmpptr<tooFar) && ( *(tmpptr++) != Element::OBJECT_END_AMF0)
) {
-// log_debug("Looking for end of object...");
- }
- break;
- case Element::MOVIECLIP_AMF0:
- case Element::NULL_AMF0:
- el->makeUndefined();
- break;
- case Element::UNDEFINED_AMF0:
- el->makeUndefined();
- break;
- case Element::REFERENCE_AMF0:
- case Element::ECMA_ARRAY_AMF0:
- // FIXME this shouldn't fall thru
- case Element::OBJECT_END_AMF0:
-// log_debug(_("End of Object definition"));
- el->makeObjectEnd();
- break;
- case Element::TYPED_OBJECT_AMF0:
- el->makeTypedObject(tmpptr, 0); // TODO: pass tooFar over ?
- break;
- case Element::STRICT_ARRAY_AMF0:
- case Element::DATE_AMF0:
- el->makeDate(tmpptr); // TODO: pass tooFar over ?
- break;
- case Element::LONG_STRING_AMF0:
- case Element::UNSUPPORTED_AMF0:
- case Element::RECORD_SET_AMF0:
- case Element::XML_OBJECT_AMF0:
- default:
- log_unimpl(_("amf0_type_e of value: %x"), (int)type);
- delete el;
- return 0;
}
+ delete name;
+
// Calculate the offset for the next read
- _totalsize = (tmpptr - in) + 1;
-// log_debug("Total number of bytes read from byte stream is: %d",
_totalsize);
+ _totalsize = (tmpptr - in);
return el;
}
Index: libamf/amf.h
===================================================================
RCS file: /sources/gnash/gnash/libamf/amf.h,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -b -r1.42 -r1.43
--- libamf/amf.h 30 Apr 2008 18:19:40 -0000 1.42
+++ libamf/amf.h 16 May 2008 03:46:19 -0000 1.43
@@ -65,6 +65,12 @@
// For terminating sequences, a byte with value 0x09 is used.
const gnash::Network::byte_t TERMINATOR = 0x09;
+// As if there is a parsing error, we'll often see the symptom of the length
+// for the following value is bogus. Although the length field is a short, it
+// seems silly to assume we'll ever see a string 65,000 characters long. Still,
+// it makes sense to make this an adjustable thing.
+const int SANE_STR_SIZE = 1024;
+
// An AMF object is the binary representation of an ActionScript object. AMF
// is used to send objects, wheather to a SharedObject .sol file, a memory
based
// LocalConnection segment, or over an RTMP connection for streaming.
Index: libamf/buffer.cpp
===================================================================
RCS file: /sources/gnash/gnash/libamf/buffer.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- libamf/buffer.cpp 30 Apr 2008 03:35:30 -0000 1.9
+++ libamf/buffer.cpp 16 May 2008 03:46:20 -0000 1.10
@@ -29,6 +29,51 @@
namespace amf
{
+#if 0
+// convert an ascii hex digit to a number.
+// param is hex digit.
+// returns a decimal digit.
+Network::byte_t
+hex2digit (Network::byte_t digit)
+{
+ if (digit == 0)
+ return 0;
+
+ if (digit >= '0' && digit <= '9')
+ return digit - '0';
+ if (digit >= 'a' && digit <= 'f')
+ return digit - 'a' + 10;
+ if (digit >= 'A' && digit <= 'F')
+ return digit - 'A' + 10;
+
+ // shouldn't ever get this far
+ return -1;
+}
+
+// Convert the hex array pointed to by buf into binary to be placed in mem
+Buffer *
+Buffer::hex2mem(const char *str)
+{
+ size_t count = strlen(str);
+ Network::byte_t ch = 0;
+ _ptr = new Buffer((count/3)+1);
+// buf->clear();
+
+ Network::byte_t *strdata = const_cast<Network::byte_t
*>(reinterpret_cast<const Network::byte_t *>(str));
+
+ for (size_t i=0; i<count; i++) {
+ if (*strdata == ' ') { // skip spaces.
+ strdata++;
+ continue;
+ }
+ ch = hex2digit(*strdata++) << 4;
+ ch |= hex2digit(*strdata++);
+ append(ch);
+ }
+ return _ptr;
+}
+#endif
+
void *
Buffer::init(size_t nbytes)
{
@@ -191,12 +236,8 @@
Buffer::append(boost::uint32_t num)
{
// GNASH_REPORT_FUNCTION;
- if ((_seekptr + sizeof(boost::uint32_t)) <= (_ptr + _nbytes)) {
- std::copy(&num, &num + sizeof(boost::uint32_t), _seekptr);
- _seekptr += sizeof(boost::uint32_t);
- return _seekptr;
- }
- return 0;
+ Network::byte_t *ptr = reinterpret_cast< Network::byte_t *>(&num);
+ return append(ptr, sizeof(boost::uint32_t));
}
Network::byte_t *
@@ -432,6 +473,14 @@
}
// Resize the buffer that holds the data.
+// Resize the buffer that holds the data.
+void *
+Buffer::resize()
+{
+// GNASH_REPORT_FUNCTION;
+ return resize(_seekptr - _ptr);
+}
+
void *
Buffer::resize(size_t size)
{
Index: libamf/buffer.h
===================================================================
RCS file: /sources/gnash/gnash/libamf/buffer.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- libamf/buffer.h 30 Apr 2008 03:35:30 -0000 1.6
+++ libamf/buffer.h 16 May 2008 03:46:21 -0000 1.7
@@ -45,6 +45,7 @@
bool empty() { return (_seekptr)?true:false; };
// Resize the buffer that holds the data
+ void *resize();
void *resize(size_t nbytes);
// Put data into the buffer. This overwrites all data, and resets the seek
ptr.
@@ -102,6 +103,7 @@
Buffer &operator+=(Buffer &buf);
gnash::Network::byte_t operator[](int x) { return *(_ptr + x); };
gnash::Network::byte_t *at(int x) { return _ptr + x; };
+// Buffer *hex2mem(const char *str);
// debug stuff, not need for running Cygnal
void dump();
Index: libamf/element.cpp
===================================================================
RCS file: /sources/gnash/gnash/libamf/element.cpp,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -b -r1.25 -r1.26
--- libamf/element.cpp 7 May 2008 19:22:33 -0000 1.25
+++ libamf/element.cpp 16 May 2008 03:46:21 -0000 1.26
@@ -58,8 +58,7 @@
"Recordset",
"XMLObject",
"TypedObject",
- "Varible (gnash)",
- "Function (gnash)"
+ "AMF3 Data"
};
Element::Element()
@@ -397,28 +396,29 @@
Buffer *
Element::encode()
{
-// GNASH_REPORT_FUNCTION;
+ GNASH_REPORT_FUNCTION;
Buffer *buf = 0;
if (_type == Element::OBJECT_AMF0) {
// FIXME: we probably want a better size, to avoid the other
// appends from having to resize and copy the data all the time.
- buf = new Buffer(300);
+ buf = new Buffer(300); // FIXME: calculate a sensible size
buf->clear(); // FIXME: temporary, makes buffers cleaner in
gdb.
buf->append(Element::OBJECT_AMF0);
if (_name > 0) {
-// Buffer *top = AMF::encodeElement(this);
-// buf->append(top);
- buf->append(reinterpret_cast<Network::byte_t *>(_name),
getNameSize());
size_t length = getNameSize();
boost::uint16_t enclength = length;
swapBytes(&enclength, 2);
buf->append(enclength);
+ string str = _name;
+ buf->append(str);
+ Network::byte_t byte = static_cast<Network::byte_t>(0x5);
+ buf->append(byte);
}
for (size_t i=0; i<_properties.size(); i++) {
Buffer *partial = AMF::encodeElement(_properties[i]);
- log_debug("Encoded partial size for is %d", partial->size());
- partial->dump();
+// log_debug("Encoded partial size for is %d", partial->size());
+// partial->dump();
if (partial) {
buf->append(partial);
delete partial;
@@ -426,7 +426,7 @@
break;
}
}
- log_debug("FIXME: Terminating object");
+// log_debug("FIXME: Terminating object");
Network::byte_t pad = 0;
buf->append(pad);
buf->append(pad);
@@ -485,16 +485,18 @@
{
// GNASH_REPORT_FUNCTION;
_type = Element::STRING_AMF0;
+
// Make room for an additional NULL terminator
check_buffer(size+1);
+ _buffer->clear(); // FIXME: this could be a performance issue
_buffer->copy(data, size);
// Unlike other buffers, people like to print strings, so we must add
// a NULL terminator to the string. When encoding, we are careful to
// to adjust the byte count down by one, as the NULL terminator doesn't
// get written.
- *(_buffer->end() - 1) = 0;
-
+// *(_buffer->end() - 1) = 0;
+ _buffer->setSize(size);
return *this;
}
@@ -537,6 +539,13 @@
}
Element &
+Element::makeNumber(Buffer *buf)
+{
+// GNASH_REPORT_FUNCTION;
+ return makeNumber(buf->reference());
+}
+
+Element &
Element::makeNumber(Network::byte_t *data)
{
// GNASH_REPORT_FUNCTION;
@@ -876,6 +885,14 @@
}
void
+Element::setName(const char *name, size_t size)
+{
+// GNASH_REPORT_FUNCTION;
+ Network::byte_t *ptr = reinterpret_cast<Network::byte_t *>(const_cast<char
*>(name));
+ return setName(ptr, size);
+}
+
+void
Element::setName(Network::byte_t *name, size_t size)
{
// GNASH_REPORT_FUNCTION;
@@ -945,8 +962,11 @@
case Element::RECORD_SET_AMF0:
case Element::XML_OBJECT_AMF0:
case Element::TYPED_OBJECT_AMF0:
-// cerr << "AMF data is: 0x" << hexify(_data, _length, false) << endl;
- log_debug("FIXME: got a typed object!");
+ case Element::AMF3_DATA:
+ if (getLength() != 0) {
+ log_debug("FIXME: got AMF3 data!");
+ }
+// cerr << "AMF3 data is: 0x" << hexify(_data, _length, false) << endl;
break;
// case Element::VARIABLE:
// case Element::FUNCTION:
@@ -959,6 +979,19 @@
// log_unimpl("%s: type %d", __PRETTY_FUNCTION__, (int)_type);
break;
}
+
+ if (_buffer) {
+ _buffer->dump();
+ }
+
+ if (_properties.size() > 0) {
+ vector<amf::Element *>::iterator ait;
+ cerr << "# of Properties in object" << _properties.size() << endl;
+ for (ait = _properties.begin(); ait != _properties.end(); ait++) {
+ amf::Element *el = (*(ait));
+ el->dump();
+ }
+ }
}
} // end of amf namespace
Index: libamf/element.h
===================================================================
RCS file: /sources/gnash/gnash/libamf/element.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22
--- libamf/element.h 3 May 2008 18:44:06 -0000 1.21
+++ libamf/element.h 16 May 2008 03:46:22 -0000 1.22
@@ -55,8 +55,9 @@
RECORD_SET_AMF0=0x0e,
XML_OBJECT_AMF0=0x0f,
TYPED_OBJECT_AMF0=0x10,
+ AMF3_DATA=0x11,
// // these aren't part of the AMF spec, they're used internally
-// VARIABLE=0x11,
+ RTMP_HEADER=0x20,
// FUNCTION=0x12
} amf0_type_e;
// AMF3, was introduced with ActionScript 3 in SWF version 9
@@ -107,6 +108,7 @@
Element &makeString(const std::string &name, const std::string &data);
Element &makeNumber(double num);
+ Element &makeNumber(amf::Buffer *buf);
Element &makeNumber(gnash::Network::byte_t *data);
Element &makeNumber(const std::string &name, double num);
Element &makeNumber(const std::string &name, gnash::Network::byte_t
*data);
@@ -158,6 +160,8 @@
Element &makeStrictArray(gnash::Network::byte_t *data, size_t size);
// Element &makeArray();
+// Element &makeConnect();
+
// Test to see if Elements are the same
bool operator==(Element &);
bool operator==(Element *);
@@ -188,6 +192,7 @@
size_t getNameSize();
void setName(const std::string &name);
void setName(gnash::Network::byte_t *name, size_t x);
+ void setName(const char *name, size_t x);
// Manipulate the children Elements of an object
Element *getProperty(size_t x) { return _properties[x]; };
@@ -197,7 +202,7 @@
Element *popProperty() { return _properties.front(); };
size_t propertySize() { return _properties.size(); };
amf::Buffer *encode();
-
+ std::vector<Element *> getProperties() { return _properties; };
void dump();
private:
void check_buffer(size_t size);
Index: libamf/sol.cpp
===================================================================
RCS file: /sources/gnash/gnash/libamf/sol.cpp,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -b -r1.36 -r1.37
--- libamf/sol.cpp 3 May 2008 18:44:06 -0000 1.36
+++ libamf/sol.cpp 16 May 2008 03:46:22 -0000 1.37
@@ -394,14 +394,15 @@
ptr += 4;
AMF amf_obj;
- int size = 0;
amf::Element *el;
- while ( size < static_cast<boost::uint16_t>(bodysize) - 24 ) {
+ while ( ptr < tooFar) {
if (ptr) {
el = amf_obj.extractProperty(ptr, tooFar);
if (el != 0) {
- size += amf_obj.totalsize();
- ptr += amf_obj.totalsize();
+ // Unlike RTMP, SOL files tack an extra
+ // zero byte after every property, so we
+ // want to skip past this one too.
+ ptr += amf_obj.totalsize() + 1;
_amfobjs.push_back(el);
} else {
break;
@@ -446,15 +447,16 @@
}
if (el->getType() == Element::NUMBER_AMF0) {
double ddd = *((double *)el->getData());
+ swapBytes(&ddd, sizeof(double));
cerr << ddd << " ";
cerr << "( " << hexify(el->getData(), 8, false) << ")";
}
- if ((*(it))->getType() == Element::BOOLEAN_AMF0) {
- if (el[0] == true) {
+ if (el->getType() == Element::BOOLEAN_AMF0) {
+ if (el->to_bool() == true) {
cerr << "true";
}
- if (el[0] == false) {
+ if (el->to_bool() == false) {
cerr << "false";
}
}
Index: libamf/sol.h
===================================================================
RCS file: /sources/gnash/gnash/libamf/sol.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -b -r1.13 -r1.14
--- libamf/sol.h 30 Apr 2008 03:35:31 -0000 1.13
+++ libamf/sol.h 16 May 2008 03:46:23 -0000 1.14
@@ -77,10 +77,7 @@
void addObj(amf::Element *x);
/// Return a reference to the elements in this object
- std::vector<amf::Element *>& getElements()
- {
- return _amfobjs;
- }
+ std::vector<amf::Element *>& getElements() { return _amfobjs; }
/// Get an element by index
//
Index: libnet/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/libnet/Makefile.am,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- libnet/Makefile.am 1 Apr 2008 22:20:36 -0000 1.4
+++ libnet/Makefile.am 16 May 2008 03:46:24 -0000 1.5
@@ -54,6 +54,8 @@
network.h \
netstats.h \
rtmp.h \
+ rtmp_msg.h \
+ rtmp_client.h \
rtmp_server.h \
statistics.h
@@ -65,6 +67,8 @@
network.cpp \
netstats.cpp \
rtmp.cpp \
+ rtmp_msg.cpp \
+ rtmp_client.cpp \
rtmp_server.cpp \
statistics.cpp
Index: libnet/handler.cpp
===================================================================
RCS file: /sources/gnash/gnash/libnet/handler.cpp,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -b -r1.6 -r1.7
--- libnet/handler.cpp 3 May 2008 18:44:08 -0000 1.6
+++ libnet/handler.cpp 16 May 2008 03:46:24 -0000 1.7
@@ -220,7 +220,7 @@
}
// ret is "no position" when the socket is closed from the other end of
the connection,
// so we're done.
- if ((ret == string::npos) || (ret == -1)) {
+ if ((ret == string::npos) || (ret == 0xffffffff)) {
log_debug("socket for fd #%d was closed...", args->netfd);
break;
}
Index: libnet/http.cpp
===================================================================
RCS file: /sources/gnash/gnash/libnet/http.cpp,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -b -r1.9 -r1.10
--- libnet/http.cpp 30 Apr 2008 03:48:52 -0000 1.9
+++ libnet/http.cpp 16 May 2008 03:46:25 -0000 1.10
@@ -173,7 +173,7 @@
bool
-HTTP::formatHeader(int filesize, http_status_e type)
+HTTP::formatHeader(int filesize, http_status_e /* type */)
{
// GNASH_REPORT_FUNCTION;
@@ -389,6 +389,7 @@
HTTP::formatLastModified(const string &date)
{
_header << "Last-Modified: " << date << "\r\n";
+ return true;
}
bool
@@ -473,7 +474,7 @@
}
bool
-HTTP::sendPostReply(rtmpt_cmd_e code)
+HTTP::sendPostReply(rtmpt_cmd_e /* code */)
{
GNASH_REPORT_FUNCTION;
@@ -660,7 +661,7 @@
// force the case to make comparisons easier
// std::transform(body.begin(), body.end(), body.begin(),
// (int(*)(int)) toupper);
- string::size_type start, end;
+ string::size_type start;
// Extract the command
start = body.find("GET", 0);
@@ -705,7 +706,7 @@
// GNASH_REPORT_FUNCTION;
string body = reinterpret_cast<const char *>(data);
- string::size_type start, end, length, pos;
+ string::size_type start, end;
string pattern = "Accept-Ranges: ";
start = body.find(pattern, 0);
if (start == string::npos) {
@@ -1190,7 +1191,6 @@
httphandler(Handler::thread_params_t *args)
{
GNASH_REPORT_FUNCTION;
- int retries = 10;
// struct thread_params thread_data;
string url, filespec, parameters;
string::size_type pos;
@@ -1216,7 +1216,8 @@
log_debug("Not waiting no more, no more for more HTTP data for fd
#%d...", args->netfd);
map<int, Handler *>::iterator hit = handlers.find(args->netfd);
if ((*hit).second) {
- log_debug("Removing handle %x for HTTP on fd #%d", (void
*)hand), args->netfd;
+ log_debug("Removing handle %x for HTTP on fd #%d",
+ (void *)hand, args->netfd);
handlers.erase(args->netfd);
delete (*hit).second;
}
@@ -1266,7 +1267,8 @@
log_debug (_("File to load is: %s"), filespec.c_str());
log_debug (_("Parameters are: %s"), parameters.c_str());
struct stat st;
- int filefd, ret;
+ int filefd;
+ size_t ret;
#ifdef USE_STATISTICS
struct timespec start;
clock_gettime (CLOCK_REALTIME, &start);
Index: libnet/rtmp.cpp
===================================================================
RCS file: /sources/gnash/gnash/libnet/rtmp.cpp,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- libnet/rtmp.cpp 3 May 2008 18:44:08 -0000 1.10
+++ libnet/rtmp.cpp 16 May 2008 03:46:25 -0000 1.11
@@ -154,91 +154,15 @@
return el;
}
}
+ return 0;
}
-// A request for a handshake is initiated by sending a byte with a
-// value of 0x3, followed by a message body of unknown format.
-bool
-RTMP::handShakeRequest()
-{
- GNASH_REPORT_FUNCTION;
-
-#if 0
- char buffer[RTMP_BODY_SIZE+1];
- char c = 0x3;
- int i, ret;
-
- ret = writeNet(&c, 1);
- _outbytes += 1;
- // something went wrong, chances are the other end of the network
- // connection is down, or never initialized.
- if (ret <= 0) {
- return false;
- }
-
- // Since we don't know what the format is, create a pattern we can
- // recognize if we stumble across it later on.
- for (i=0; i<RTMP_BODY_SIZE; i++) {
- buffer[i] = i^256;
- }
-
- _outbytes += RTMP_BODY_SIZE;
- ret = writeNet(buffer, RTMP_BODY_SIZE);
-#endif
-
- return true;
-}
-
-// The client finished the handshake process by sending the second
-// data block we get from the server as the response
-bool
-RTMP::clientFinish()
-{
- GNASH_REPORT_FUNCTION;
-
-#if 0
- char buffer[RTMP_BODY_SIZE+1];
- memset(buffer, 0, RTMP_BODY_SIZE+1);
-
- if (readNet(buffer, RTMP_BODY_SIZE) == RTMP_BODY_SIZE) {
- log_debug (_("Read first data block in handshake"));
- } else {
- log_error (_("Couldn't read first data block in handshake"));
- return false;
- }
- _inbytes += RTMP_BODY_SIZE;
- if (readNet(buffer, RTMP_BODY_SIZE) == RTMP_BODY_SIZE) {
- log_debug (_("Read second data block in handshake"));
-// _body = new char(RTMP_BODY_SIZE+1);
-// memcpy(_body, buffer, RTMP_BODY_SIZE);
- } else {
- log_error (_("Couldn't read second data block in handshake"));
- return false;
- }
- _inbytes += RTMP_BODY_SIZE;
-
- writeNet(buffer, RTMP_BODY_SIZE);
- _outbytes += RTMP_BODY_SIZE;
-#endif
-
- return true;
-}
-
-bool
-RTMP::packetRequest()
-{
- GNASH_REPORT_FUNCTION;
- return false;
-}
-
-#if 0
-bool
-RTMP::packetSend(amf::Buffer * /* buf */)
+RTMP::rtmp_head_t *
+RTMP::decodeHeader(Buffer *buf)
{
GNASH_REPORT_FUNCTION;
- return false;
+ return decodeHeader(buf->reference());
}
-#endif
RTMP::rtmp_head_t *
RTMP::decodeHeader(Network::byte_t *in)
@@ -251,12 +175,13 @@
log_debug (_("The AMF channel index is %d"), _header.channel);
_header.head_size = headerSize(*tmpptr++);
- printf (_("The header size is %d"), _header.head_size);
+ log_debug (_("The header size is %d"), _header.head_size);
if (_header.head_size >= 4) {
_mystery_word = *tmpptr++;
_mystery_word = (_mystery_word << 12) + *tmpptr++;
_mystery_word = (_mystery_word << 8) + *tmpptr++;
+
log_debug(_("The mystery word is: %d"), _mystery_word);
}
@@ -295,7 +220,7 @@
// };
if (_header.head_size == 12) {
- _header.src_dest = *(reinterpret_cast<rtmp_source_e *>(tmpptr));
+ _header.src_dest = *(reinterpret_cast<RTMPMsg::rtmp_source_e
*>(tmpptr));
tmpptr += sizeof(unsigned int);
log_debug(_("The source/destination is: %x"), _header.src_dest);
}
@@ -310,11 +235,26 @@
/// * Type - The type of the message
/// * Routing - The source/destination of the message
//
+
+amf::Buffer *
+RTMP::encodeHeader(int amf_index, rtmp_headersize_e head_size)
+{
+ GNASH_REPORT_FUNCTION;
+ amf::Buffer *buf = new Buffer(1);
+ Network::byte_t *ptr = buf->reference();
+
+ // Make the channel index & header size byte
+ *ptr = head_size & RTMP_HEADSIZE_MASK;
+ *ptr += amf_index & RTMP_INDEX_MASK;
+
+ return buf;
+}
+
// There are 3 size of RTMP headers, 1, 4, 8, and 12.
amf::Buffer *
RTMP::encodeHeader(int amf_index, rtmp_headersize_e head_size,
size_t total_size, content_types_e type,
- rtmp_source_e routing)
+ RTMPMsg::rtmp_source_e routing)
{
GNASH_REPORT_FUNCTION;
@@ -390,7 +330,7 @@
GNASH_REPORT_FUNCTION;
// int packetsize = 0;
- unsigned int amf_index, headersize;
+ size_t amf_index, headersize;
Network::byte_t *ptr = buf->reference();
Network::byte_t *tooFar = ptr+buf->size();
AMF amf;
@@ -423,15 +363,15 @@
// ptr += headersize;
amf::Element *el = amf.extractAMF(ptr, tooFar);
- el->dump();
+// el->dump();
el = amf.extractAMF(ptr, tooFar) + 1; // @@strk@@ : what's the +1 for ?
- el->dump();
+// el->dump();
log_debug (_("Reading AMF packets till we're done..."));
- buf->dump();
+// buf->dump();
while (ptr < end) {
amf::Element *el = amf.extractProperty(ptr, tooFar);
addProperty(el);
- el->dump();
+// el->dump();
}
ptr += 1;
size_t actual_size = static_cast<size_t>(_header.bodysize -
AMF_HEADER_SIZE);
@@ -441,13 +381,13 @@
log_debug("FIXME: MERGING");
buf = _handler->merge(buf);
}
- while ((ptr - buf->begin()) < actual_size) {
+ while ((ptr - buf->begin()) < static_cast<int>(actual_size)) {
amf::Element *el = amf.extractProperty(ptr, tooFar);
addProperty(el);
- el->dump(); // FIXME: dump the AMF objects as they are read
in
+// el->dump(); // FIXME: dump the AMF objects as they are read
in
}
- dump();
+// dump();
amf::Element *url = getProperty("tcUrl");
amf::Element *file = getProperty("swfUrl");
@@ -494,75 +434,12 @@
// type 6: Ping the client from server. The second parameter is the current
time.
// type 7: Pong reply from client. The second parameter is the time the server
sent with his
// ping request.
-amf::Buffer *
-RTMP::encodeChunkSize()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMP::decodeChunkSize()
-{
- GNASH_REPORT_FUNCTION;
-}
-amf::Buffer *
-RTMP::encodeBytesRead()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMP::decodeBytesRead()
-{
- GNASH_REPORT_FUNCTION;
-}
-
-// A RTMP Ping packet looks like this: "03 00 00 00 00 00 00 0B B8", which is
the
-// Ping type byte, followed by two shorts that are the parameters. Only the
first
+// A RTMP Ping packet looks like this: "02 00 00 00 00 00 06 04 00 00 00 00 00
00 00 00 00 0",
+// which is the Ping type byte, followed by two shorts that are the
parameters. Only the first
// two paramters are required.
-amf::Buffer *
-RTMP::encodePing(rtmp_ping_e type, boost::uint16_t milliseconds)
-{
- GNASH_REPORT_FUNCTION;
- Buffer *buf = new Buffer(sizeof(boost::uint16_t) * 4);
- Network::byte_t *ptr = buf->reference();
- buf->clear(); // default everything to zeros, real data gets
optionally added.
- boost::uint16_t typefield = *reinterpret_cast<boost::uint16_t *>(&type);
- ptr += sizeof(boost::uint16_t); // go past the first short
-
- boost::uint16_t swapped = 0;
- buf->copy(typefield);
- switch (type) {
- // These two don't appear to have any paramaters
- case PING_CLEAR:
- case PING_PLAY:
- break;
- // the third parameter is the buffer time in milliseconds
- case PING_TIME:
- {
- ptr += sizeof(boost::uint16_t); // go past the second short
- swapped = htons(milliseconds);
- buf->append(swapped);
- break;
- }
- // reset doesn't have any parameters
- case PING_RESET:
- break;
- // For Ping and Pong, the second parameter is always the milliseconds
- case PING_CLIENT:
- case PONG_CLIENT:
- {
- swapped = htons(milliseconds);
-// std::copy(&swapped, &swapped + sizeof(boost::uint16_t), ptr);
- buf->append(swapped);
- break;
- }
- default:
- return 0;
- break;
- };
-
- return buf;
-}
+// This seems to be a ping message, 12 byte header, system channel 2
+// 02 00 00 00 00 00 06 04 00 00 00 00 00 00 00 00 00 00
RTMP::rtmp_ping_t *
RTMP::decodePing(Network::byte_t *data)
{
@@ -572,17 +449,22 @@
rtmp_ping_t *ping = new rtmp_ping_t;
memset(ping, 0, sizeof(rtmp_ping_t));
- boost::uint16_t type = *reinterpret_cast<rtmp_ping_e *>(ptr);
+ // All the data fields in a ping message are 2 bytes long.
+ boost::uint16_t type = ntohs(*reinterpret_cast<rtmp_ping_e *>(ptr));
ping->type = static_cast<rtmp_ping_e>(type);
ptr += sizeof(boost::uint16_t);
- ping->target = *reinterpret_cast<boost::uint16_t *>(ptr);
+ ping->target = ntohs(*reinterpret_cast<boost::uint16_t *>(ptr));
ptr += sizeof(boost::uint16_t);
ping->param1 = ntohs(*reinterpret_cast<boost::uint16_t *>(ptr));
ptr += sizeof(boost::uint16_t);
- ping->param1 = ntohs(*reinterpret_cast<boost::uint16_t *>(ptr));
+// ping->param2 = ntohs(*reinterpret_cast<boost::uint16_t *>(ptr));
+// ptr += sizeof(boost::uint16_t);
+
+// ping->param3 = ntohs(*reinterpret_cast<boost::uint16_t *>(ptr));
+ ping->param3 = 0;
return ping;
}
@@ -593,81 +475,246 @@
return decodePing(buf->reference());
}
+// Decode the result we get from the server after we've made a request.
+//
+// 03 00 00 00 00 00 81 14 00 00 00 00 02 00 07 5f ..............._
+// 72 65 73 75 6c 74 00 3f f0 00 00 00 00 00 00 05 result.?........
+// 03 00 0b 61 70 70 6c 69 63 61 74 69 6f 6e 05 00 ...application..
+// 05 6c 65 76 65 6c 02 00 06 73 74 61 74 75 73 00 .level...status.
+// 0b 64 65 73 63 72 69 70 74 69 6f 6e 02 00 15 43 .description...C
+// 6f 6e 6e 65 63 74 69 6f 6e 20 73 75 63 63 65 65 onnection succee
+// 64 65 64 2e 00 04 63 6f 64 65 02 00 1d 4e 65 74 ded...code...Net
+// 43 6f 6e 6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 Connection.Conne
+// 63 74 2e 53 75 63 63 65 73 73 00 00 c3 09 ct.Success....
+//
+// 43 00 00 00 00 00 48 14 02 00 06 5f 65 72 72 6f C.....H...._erro
+// 72 00 40 00 00 00 00 00 00 00 05 03 00 04 63 6f address@hidden
+// 64 65 02 00 19 4e 65 74 43 6f 6e 6e 65 63 74 69 de...NetConnecti
+// 6f 6e 2e 43 61 6c 6c 2e 46 61 69 6c 65 64 00 05 on.Call.Failed..
+// 6c 65 76 65 6c 02 00 05 65 72 72 6f 72 00 00 09 level...error...
+//
+// T 127.0.0.1:1935 -> 127.0.0.1:38167 [AP]
+// 44 00 00 00 00 00 b2 14 02 00 08 6f 6e 53 74 61 D..........onSta
+// 74 75 73 00 3f f0 00 00 00 00 00 00 05 03 00 08 tus.?...........
+// 63 6c 69 65 6e 74 69 64 00 3f f0 00 00 00 00 00 clientid.?......
+// 00 00 05 6c 65 76 65 6c 02 00 06 73 74 61 74 75 ...level...statu
+// 73 00 07 64 65 74 61 69 6c 73 02 00 16 6f 6e 32 s..details...on2
+// 5f 66 6c 61 73 68 38 5f 77 5f 61 75 64 69 6f 2e _flash8_w_audio.
+// 66 6c 76 00 0b 64 65 73 63 72 69 70 74 69 6f 6e flv..description
+// 02 00 27 53 74 61 72 74 65 64 20 70 6c 61 79 69 ..'Started playi
+// 6e 67 20 6f 6e 32 5f 66 c4 6c 61 73 68 38 5f 77 ng on2_f.lash8_w
+// 5f 61 75 64 69 6f 2e 66 6c 76 2e 00 04 63 6f 64 _audio.flv...cod
+// 65 02 00 14 4e 65 74 53 74 72 65 61 6d 2e 50 6c e...NetStream.Pl
+// 61 79 2e 53 74 61 72 74 00 00 09 ay.Start...
+//
+//
^^^_result^?^^^^^^^^^^^application^^^level^^^status^^description^^^Connection
succeeded.^^code^^^NetConnection.Connect.Success^^^^
+// 02 00 07 5f 72 65 73 75 6c 74 00 3f f0 00 00 00 00 00 00 05 03 00 0b 61 70
70 6c 69 63 61 74 69 6f 6e 05 00 05 6c 65 76 65 6c 02 00 06 73 74 61 74 75 73
00 0b 64 65 73 63 72 69 70 74 69 6f 6e 02 00 15 43 6f 6e 6e 65 63 74 69 6f 6e
20 73 75 63 63 65 65 64 65 64 2e 00 04 63 6f 64 65 02 00 1d 4e 65 74 43 6f 6e
6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 63 74 2e 53 75 63 63 65 73 73 00 00 c3
09
+// 10629:3086592224] 20:01:20 DEBUG: read 29 bytes from fd 3 from port 0
+// address@hidden
+// 43 00 00 00 00 00 15 14 02 00 08 6f 6e 42 57 44 6f 6e 65 00 40 00 00 00 00
00 00 00 05
+RTMPMsg *
+RTMP::decodeMsgBody(Network::byte_t *data, size_t size)
+{
+ GNASH_REPORT_FUNCTION;
+ AMF amf_obj;
+ Network::byte_t *ptr = data;
+ Network::byte_t* tooFar = ptr + size;
+ bool status = false;
+
+ // The first data object is the method name of this object.
+ Element *name = amf_obj.extractAMF(ptr, tooFar);
+ if (name) {
+ ptr += name->getLength() + 3; // skip the length bytes too
+ } else {
+ log_error("Name field of RTMP Message corrupted!");
+ return 0;
+ }
+
+ // The stream ID is the second data object. All messages have these two
objects
+ // at the minimum.
+ Element *streamid = amf_obj.extractAMF(ptr, tooFar);
+ if (streamid) {
+ ptr += streamid->getLength() + 2;
+ } else {
+ log_error("Stream ID field of RTMP Message corrupted!");
+ return 0;
+ }
+
+ // This will need to be deleted manually later after usage, it is not
+ // automatically deallocated.
+ RTMPMsg *msg = new RTMPMsg;
+
+ msg->setMethodName(name->to_string());
+ double swapped = streamid->to_number();
+ swapBytes(&swapped, amf::AMF0_NUMBER_SIZE);
+ msg->setStreamID(swapped);
+
+ if ((msg->getMethodName() == "_result") || (msg->getMethodName() ==
"error")) {
+ status = true;
+ }
+
+ // Then there are a series of AMF objects, often a higher level
ActionScript object with
+ // properties attached.
+ while (ptr < tooFar) {
+ // These pointers get deleted automatically when the msg object is
deleted
+ amf::Element *el = amf_obj.extractAMF(ptr, tooFar);
+ if (el == 0) {
+ break;
+ }
+// el->dump();
+ msg->addObject(el);
+ if (status) {
+ msg->checkStatus(el);
+ }
+ ptr += amf_obj.totalsize();
+ };
+
+ // cleanup after ourselves
+ delete name;
+ delete streamid;
+
+ return msg;
+}
+
+RTMPMsg *
+RTMP::decodeMsgBody(amf::Buffer *buf)
+{
+// GNASH_REPORT_FUNCTION;
+ return decodeMsgBody(buf->reference(), buf->size());
+}
+
+amf::Buffer *
+RTMP::encodeChunkSize()
+{
+ GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
+}
+
+void
+RTMP::decodeChunkSize()
+{
+ GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+}
+
+amf::Buffer *
+RTMP::encodeBytesRead()
+{
+ GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
+}
+
+void
+RTMP::decodeBytesRead()
+{
+ GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+}
+
amf::Buffer *
RTMP::encodeServer()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
+
void
RTMP::decodeServer()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
amf::Buffer *
RTMP::encodeClient()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
+
void
RTMP::decodeClient()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
amf::Buffer *
RTMP::encodeAudioData()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
+
void
RTMP::decodeAudioData()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
amf::Buffer *
RTMP::encodeVideoData()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
+
void
RTMP::decodeVideoData()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
amf::Buffer *
RTMP::encodeNotify()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
+
void
RTMP::decodeNotify()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
amf::Buffer *
RTMP::encodeSharedObj()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
+
void
RTMP::decodeSharedObj()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
amf::Buffer *
RTMP::encodeInvoke()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
}
void
RTMP::decodeInvoke()
{
GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
}
} // end of gnash namespace
Index: libnet/rtmp.h
===================================================================
RCS file: /sources/gnash/gnash/libnet/rtmp.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- libnet/rtmp.h 3 May 2008 18:44:08 -0000 1.8
+++ libnet/rtmp.h 16 May 2008 03:46:26 -0000 1.9
@@ -20,14 +20,14 @@
#include <boost/cstdint.hpp>
#include <string>
-#include <map>
+#include <vector>
#include "amf.h"
#include "element.h"
#include "handler.h"
#include "network.h"
#include "buffer.h"
-#include "amfutf8.h"
+#include "rtmp_msg.h"
namespace gnash
{
@@ -41,6 +41,7 @@
const int RTMP_VIDEO_PACKET_SIZE = 128;
const int RTMP_AUDIO_PACKET_SIZE = 64;
const int RTMP_MAX_HEADER_SIZE = 12;
+const int PING_MSG_SIZE = 6;
// For terminating sequences, a byte with value 0x09 is used.
const char TERMINATOR = 0x09;
@@ -73,14 +74,22 @@
class DSOEXPORT RTMP
{
public:
+ typedef enum {
+ RAW=0x0,
+ ADPCM=0x01,
+ MP3=0x02,
+ NELLYMOSER_8khz=0x05,
+ NEYYNOSER=0x6
+ } audiocodecs_e;
+ typedef enum {
+ H263=0x2,
+ SCREEN0x3,
+ VP6=0x4
+ } videocodecs_e;
// The second byte of the AMF file/stream is appears to be 0x00 if the
// client is the Flash Player and 0x01 if the client is the FlashCom
// server.
typedef enum {
- FROM_CLIENT, // Flash player
- FROM_SERVER // Flash com server
- } rtmp_source_e;
- typedef enum {
NONE = 0x0,
CHUNK_SIZE = 0x1,
UNKNOWN = 0x2,
@@ -119,9 +128,10 @@
} rtmp_ping_e;
typedef struct {
rtmp_ping_e type; // the type of the ping message
- boost::uint16_t target;
- boost::uint16_t param1;
+ boost::uint16_t target; // all Ping message data fields
+ boost::uint16_t param1; // are 2 bytes long
boost::uint16_t param2;
+ boost::uint16_t param3;
} rtmp_ping_t;
typedef enum {
RTMP_STATE_HANDSHAKE_SEND,
@@ -133,6 +143,12 @@
RTMP_STATE_HEADER,
RTMP_STATE_DONE
} rtmp_state_t;
+// typedef struct {
+// rtmp_status_e status;
+// std::string method;
+// double streamid;
+// std::vector<amf::Element *> objs;
+// } rtmp_msg_t;
typedef enum {
RTMP_ERR_UNDEF=0,
RTMP_ERR_NOTFOUND,
@@ -156,7 +172,7 @@
int channel;
int head_size;
int bodysize;
- rtmp_source_e src_dest;
+ RTMPMsg::rtmp_source_e src_dest;
content_types_e type;
} rtmp_head_t;
typedef enum {
@@ -172,25 +188,23 @@
// * UTF String - Response
// * Long - Body length in bytes
// * Variable - Actual data (including a type code)
- typedef struct {
- amf::amfutf8_t target;
- amf::amfutf8_t response;
- boost::uint32_t length;
- void *data;
- } rtmp_body_t;
+// typedef struct {
+// amf::amfutf8_t target;
+// amf::amfutf8_t response;
+// boost::uint32_t length;
+// void *data;
+// } rtmp_body_t;
RTMP();
- ~RTMP();
+ virtual ~RTMP();
// Decode
rtmp_head_t *decodeHeader(gnash::Network::byte_t *header);
rtmp_head_t *decodeHeader(amf::Buffer *data);
amf::Buffer *encodeHeader(int amf_index, rtmp_headersize_e head_size,
- size_t total_size, content_types_e type,
rtmp_source_e routing);
+ size_t total_size, content_types_e type,
RTMPMsg::rtmp_source_e routing);
+ amf::Buffer *encodeHeader(int amf_index, rtmp_headersize_e head_size);
- bool handShakeRequest();
- bool clientFinish();
- bool packetRequest();
bool packetSend(amf::Buffer *buf);
bool packetRead(amf::Buffer *buf);
@@ -204,22 +218,24 @@
rtmp_head_t *getHeader() { return &_header; };
int getHeaderSize() { return _header.head_size; };
int getTotalSize() { return _header.bodysize; };
- rtmp_source_e getRouting() { return _header.src_dest; };
+ RTMPMsg::rtmp_source_e getRouting() { return _header.src_dest; };
int getChannel() { return _header.channel; };
int getPacketSize() { return _packet_size; };
int getMysteryWord() { return _mystery_word; };
+ // Decode the an RTMP message
+ RTMPMsg *decodeMsgBody(Network::byte_t *data, size_t size);
+ RTMPMsg *decodeMsgBody(amf::Buffer *buf);
+
+ virtual rtmp_ping_t *decodePing(Network::byte_t *data);
+ rtmp_ping_t *decodePing(amf::Buffer *buf);
+
// These are handlers for the various types
virtual amf::Buffer *encodeChunkSize();
virtual void decodeChunkSize();
virtual amf::Buffer *encodeBytesRead();
virtual void decodeBytesRead();
-
- virtual amf::Buffer *encodePing(rtmp_ping_e type, boost::uint16_t
milliseconds);
- virtual rtmp_ping_t *decodePing(Network::byte_t *data);
- rtmp_ping_t *decodePing(amf::Buffer *buf);
-
virtual amf::Buffer *encodeServer();
virtual void decodeServer();
Index: libnet/rtmp_server.cpp
===================================================================
RCS file: /sources/gnash/gnash/libnet/rtmp_server.cpp,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- libnet/rtmp_server.cpp 3 May 2008 18:44:08 -0000 1.5
+++ libnet/rtmp_server.cpp 16 May 2008 03:46:32 -0000 1.6
@@ -24,6 +24,7 @@
#include <iostream>
#include <string>
#include <map>
+#include <boost/cstdint.hpp>
#if ! (defined(_WIN32) || defined(WIN32))
# include <netinet/in.h>
@@ -92,7 +93,7 @@
// secret = _handler->merge(buf->reference());
// }
- if (buf->size() >= RTMP_BODY_SIZE) {
+ if (buf->size() >= static_cast<size_t>(RTMP_BODY_SIZE)) {
_handshake = new amf::Buffer(RTMP_BODY_SIZE);
_handshake->copy(buf->reference() + 1, RTMP_BODY_SIZE);
log_debug (_("Handshake Data matched"));
@@ -149,7 +150,7 @@
// The first data packet is often buried in with the end of the handshake.
// So after the handshake block, we strip that part off, and just pass on
// the remainder for processing.
- if (buf->size() > RTMP_BODY_SIZE) {
+ if (buf->size() >= static_cast<size_t>(RTMP_BODY_SIZE)) {
size_t size = buf->size() - RTMP_BODY_SIZE;
obj = new amf::Buffer[size];
obj->copy(buf->begin()+RTMP_BODY_SIZE, size);
@@ -184,8 +185,6 @@
{
GNASH_REPORT_FUNCTION;
- int ret;
- int packetsize = 0;
unsigned int amf_index, headersize;
Network::byte_t *ptr = buf->reference();
AMF amf;
@@ -206,14 +205,14 @@
// }
// }
-#if 1
- Network::byte_t *end = buf->remove(0xc3);
-#else
- Network::byte_t *end = buf->find(0xc3);
- log_debug("END is %x", (void *)end);
- *end = '*';
-#endif
- rtmp_head_t *head = decodeHeader(ptr);
+// #if 1
+// Network::byte_t *end = buf->remove(0xc3);
+// #else
+// Network::byte_t *end = buf->find(0xc3);
+// log_debug("END is %x", (void *)end);
+// *end = '*';
+// #endif
+ decodeHeader(ptr);
ptr += headersize;
Network::byte_t* tooFar = ptr+300+sizeof(int); // FIXME:
@@ -241,6 +240,9 @@
}
}
+ delete el1;
+ delete el2;
+
# if 0
Element el;
ptr = amf.extractElement(&el, ptr);
@@ -348,107 +350,160 @@
return true;
}
-#if 0
-// These process the incoming AMF object types from the data stream
+// A result packet looks like this:
+//
+// 03 00 00 00 00 00 81 14 00 00 00 00 02 00 07 5f ..............._
+// 72 65 73 75 6c 74 00 3f f0 00 00 00 00 00 00 05 result.?........
+// 03 00 0b 61 70 70 6c 69 63 61 74 69 6f 6e 05 00 ...application..
+// 05 6c 65 76 65 6c 02 00 06 73 74 61 74 75 73 00 .level...status.
+// 0b 64 65 73 63 72 69 70 74 69 6f 6e 02 00 15 43 .description...C
+// 6f 6e 6e 65 63 74 69 6f 6e 20 73 75 63 63 65 65 onnection succee
+// 64 65 64 2e 00 04 63 6f 64 65 02 00 1d 4e 65 74 ded...code...Net
+// 43 6f 6e 6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 Connection.Conne
+// 63 74 2e 53 75 63 63 65 73 73 00 00 c3 09 ct.Success....
+//
+// _result(double ClientStream, NULL, double ServerStream)
+// These are handlers for the various types
amf::Buffer *
-RTMPServer::encodeChunkSize()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeChunkSize()
+RTMPServer::encodeResult(RTMPMsg::rtmp_status_e status)
{
GNASH_REPORT_FUNCTION;
-}
-amf::Buffer *
-RTMPServer::encodeBytesRead()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeBytesRead()
-{
- GNASH_REPORT_FUNCTION;
-}
-
-amf::Buffer *
-RTMPServer::encodeServer()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeServer()
-{
- GNASH_REPORT_FUNCTION;
-}
-
-amf::Buffer *
-RTMPServer::encodeClient()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeClient()
-{
- GNASH_REPORT_FUNCTION;
-}
-
-amf::Buffer *
-RTMPServer::encodeAudioData()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeAudioData()
-{
- GNASH_REPORT_FUNCTION;
-}
-
-amf::Buffer *
-RTMPServer::encodeVideoData()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeVideoData()
-{
- GNASH_REPORT_FUNCTION;
-}
-
-amf::Buffer *
-RTMPServer::encodeNotify()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeNotify()
-{
- GNASH_REPORT_FUNCTION;
-}
+// Buffer *buf = new Buffer;
+// Network::byte_t *ptr = buf->reference();
+// buf->clear(); // default everything to zeros, real data gets
optionally added.
+// ptr += sizeof(boost::uint16_t); // go past the first short
+// const char *capabilities = 0;
+// const char *description = 0;
+// const char *code = 0;
+// const char *status = 0;
+
+ Element *str = new Element;
+ str->makeString("_result");
+
+ Element *number = new Element;
+ // add The server ID
+ number->makeNumber(1); // FIXME: needs a real value, which should
increment
+
+ Element top;
+ top.makeObject("application");
+
+ switch (status) {
+ case RTMPMsg::APP_GC:
+ case RTMPMsg::APP_RESOURCE_LOWMEMORY:
+ case RTMPMsg::APP_SCRIPT_ERROR:
+ case RTMPMsg::APP_SCRIPT_WARNING:
+ case RTMPMsg::APP_SHUTDOWN:
+ case RTMPMsg::NC_CALL_BADVERSION:
+ case RTMPMsg::NC_CALL_FAILED:
+// status = 0;
+// code = "NetConnection.Call.Failed";
+ case RTMPMsg::NC_CONNECT_APPSHUTDOWN:
+ case RTMPMsg::NC_CONNECT_CLOSED:
+ case RTMPMsg::NC_CONNECT_FAILED:
+ {
+// errstr = new Element;
+// errstr->makeString("error");
+ Element *level = new Element;
+ level->makeString("level", "error");
+ top.addProperty(level);
+
+ Element *description = new Element;
+ description->makeString("description", "Connection Failed.");
+ top.addProperty(description);
+
+ Element *code = new Element;
+ code->makeString("code", "Connection.Connect.Failed");
+ top.addProperty(code);
+ }
+ case RTMPMsg::NC_CONNECT_INVALID_APPLICATION:
+ case RTMPMsg::NC_CONNECT_REJECTED:
+ {
+// delete str;
+// str = new Element;
+// str->makeString("error");
+ Element *level = new Element;
+ level->makeString("level", "error");
+ top.addProperty(level);
+
+ Element *description = new Element;
+ description->makeString("description", "Connection Rejected.");
+ top.addProperty(description);
+
+ Element *code = new Element;
+ code->makeString("code", "NetConnection.Connect.Rejected");
+ top.addProperty(code);
+ }
+ case RTMPMsg::NC_CONNECT_SUCCESS:
+ {
+ Element *level = new Element;
+ level->makeString("level", "status");
+ top.addProperty(level);
+
+ Element *description = new Element;
+ description->makeString("description", "Connection succeeded.");
+ top.addProperty(description);
+
+ Element *code = new Element;
+ code->makeString("code", "NetConnection.Connect.Success");
+ top.addProperty(code);
+ }
+ break;
+ case RTMPMsg::NS_CLEAR_FAILED:
+ case RTMPMsg::NS_CLEAR_SUCCESS:
+ case RTMPMsg::NS_DATA_START:
+ case RTMPMsg::NS_FAILED:
+ case RTMPMsg::NS_INVALID_ARGUMENT:
+ case RTMPMsg::NS_PAUSE_NOTIFY:
+ case RTMPMsg::NS_PLAY_COMPLETE:
+ case RTMPMsg::NS_PLAY_FAILED:
+ case RTMPMsg::NS_PLAY_FILE_STRUCTURE_INVALID:
+ case RTMPMsg::NS_PLAY_INSUFFICIENT_BW:
+ case RTMPMsg::NS_PLAY_NO_SUPPORTED_TRACK_FOUND:
+ case RTMPMsg::NS_PLAY_PUBLISHNOTIFY:
+ case RTMPMsg::NS_PLAY_RESET:
+ case RTMPMsg::NS_PLAY_START:
+ case RTMPMsg::NS_PLAY_STOP:
+ case RTMPMsg::NS_PLAY_STREAMNOTFOUND:
+ case RTMPMsg::NS_PLAY_SWITCH:
+ case RTMPMsg::NS_PLAY_UNPUBLISHNOTIFY:
+ case RTMPMsg::NS_PUBLISH_BADNAME:
+ case RTMPMsg::NS_PUBLISH_START:
+ case RTMPMsg::NS_RECORD_FAILED:
+ case RTMPMsg::NS_RECORD_NOACCESS:
+ case RTMPMsg::NS_RECORD_START:
+ case RTMPMsg::NS_RECORD_STOP:
+ case RTMPMsg::NS_SEEK_FAILED:
+ case RTMPMsg::NS_SEEK_NOTIFY:
+ case RTMPMsg::NS_UNPAUSE_NOTIFY:
+ case RTMPMsg::NS_UNPUBLISHED_SUCCESS:
+ case RTMPMsg::SO_CREATION_FAILED:
+ case RTMPMsg::SO_NO_READ_ACCESS:
+ case RTMPMsg::SO_NO_WRITE_ACCESS:
+ case RTMPMsg::SO_PERSISTENCE_MISMATCH:
+ default:
+ break;
+ };
-amf::Buffer *
-RTMPServer::encodeSharedObj()
-{
- GNASH_REPORT_FUNCTION;
-}
-void
-RTMPServer::decodeSharedObj()
-{
- GNASH_REPORT_FUNCTION;
-}
+ Buffer *strbuf = str->encode();
+ Buffer *numbuf = number->encode();
+ Buffer *topbuf = top.encode();
+
+ Buffer *buf = new Buffer(strbuf->size() + numbuf->size() + topbuf->size());
+ buf->append(strbuf);
+ buf->append(numbuf);
+ Network::byte_t byte = static_cast<Network::byte_t>(RTMP::SERVER &
0x000000ff);
+ buf->append(byte);
+ buf->append(topbuf);
+
+ delete str;
+ delete number;
+ delete strbuf;
+ delete numbuf;
+// delete topbuf;// FIXME: deleting this shouldn't core dump.
-amf::Buffer *
-RTMPServer::encodeInvoke()
-{
- GNASH_REPORT_FUNCTION;
+ return buf;
}
-void
-RTMPServer::decodeInvoke()
-{
- GNASH_REPORT_FUNCTION;
-}
-#endif
// This is the thread for all incoming RTMP connections
void
@@ -534,6 +589,78 @@
}
}
+// A Ping packet has two parameters that ae always specified, and 2 that are
optional.
+// The first two bytes are the ping type, as in rtmp_ping_e, the second is the
ping
+// target, which is always zero as far as we can tell.
+//
+// More notes from: http://jira.red5.org/confluence/display/docs/Ping
+// type 0: Clear the stream. No third and fourth parameters. The second
parameter could be 0.
+// After the connection is established, a Ping 0,0 will be sent from server to
client. The
+// message will also be sent to client on the start of Play and in response of
a Seek or
+// Pause/Resume request. This Ping tells client to re-calibrate the clock with
the timestamp
+// of the next packet server sends.
+// type 1: Tell the stream to clear the playing buffer.
+// type 3: Buffer time of the client. The third parameter is the buffer time
in millisecond.
+// type 4: Reset a stream. Used together with type 0 in the case of VOD. Often
sent before type 0.
+// type 6: Ping the client from server. The second parameter is the current
time.
+// type 7: Pong reply from client. The second parameter is the time the server
sent with his
+// ping request.
+
+// A RTMP Ping packet looks like this: "02 00 00 00 00 00 06 04 00 00 00 00 00
00 00 00 00 0",
+// which is the Ping type byte, followed by two shorts that are the
parameters. Only the first
+// two paramters are required.
+amf::Buffer *
+RTMPServer::encodePing(rtmp_ping_e type)
+{
+ GNASH_REPORT_FUNCTION;
+ return encodePing(type, 0);
+}
+
+amf::Buffer *
+RTMPServer::encodePing(rtmp_ping_e type, boost::uint32_t milliseconds)
+{
+ GNASH_REPORT_FUNCTION;
+ Buffer *buf = new Buffer(sizeof(boost::uint16_t) * 4);
+ Network::byte_t *ptr = buf->reference();
+ buf->clear(); // default everything to zeros, real data gets
optionally added.
+ boost::uint16_t typefield = *reinterpret_cast<boost::uint16_t *>(&type);
+ ptr += sizeof(boost::uint16_t); // go past the first short
+
+// boost::uint32_t swapped = 0;
+ swapBytes(&typefield, sizeof(boost::uint16_t));
+ buf->copy(typefield);
+ switch (type) {
+ // These two don't appear to have any paramaters
+ case PING_CLEAR:
+ case PING_PLAY:
+ break;
+ // the third parameter is the buffer time in milliseconds
+ case PING_TIME:
+ {
+ ptr += sizeof(boost::uint16_t); // go past the second short
+// swapped = htonl(milliseconds);
+ buf->append(htonl(milliseconds));
+ break;
+ }
+ // reset doesn't have any parameters
+ case PING_RESET:
+ break;
+ // For Ping and Pong, the second parameter is always the milliseconds
+ case PING_CLIENT:
+ case PONG_CLIENT:
+ {
+// swapped = htonl(milliseconds);
+ buf->append(htonl(milliseconds));
+ break;
+ }
+ default:
+ return 0;
+ break;
+ };
+
+ return buf;
+}
+
} // end of gnash namespace
// local Variables:
Index: libnet/rtmp_server.h
===================================================================
RCS file: /sources/gnash/gnash/libnet/rtmp_server.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libnet/rtmp_server.h 3 May 2008 18:44:08 -0000 1.3
+++ libnet/rtmp_server.h 16 May 2008 03:46:34 -0000 1.4
@@ -43,34 +43,9 @@
bool packetRead(amf::Buffer *buf);
// These are handlers for the various types
-#if 0
- amf::Buffer *encodeChunkSize();
- void decodeChunkSize();
-
- amf::Buffer *encodeBytesRead();
- void decodeBytesRead();
-
- amf::Buffer *encodeServer();
- void decodeServer();
-
- amf::Buffer *encodeClient();
- void decodeClient();
-
- amf::Buffer *encodeAudioData();
- void decodeAudioData();
-
- amf::Buffer *encodeVideoData();
- void decodeVideoData();
-
- amf::Buffer *encodeNotify();
- void decodeNotify();
-
- amf::Buffer *encodeSharedObj();
- void decodeSharedObj();
-
- amf::Buffer *encodeInvoke();
- void decodeInvoke();
-#endif
+ amf::Buffer *encodeResult(RTMPMsg::rtmp_status_e status);
+ amf::Buffer *encodePing(rtmp_ping_e type, boost::uint32_t milliseconds);
+ amf::Buffer *encodePing(rtmp_ping_e type);
void dump();
private:
Index: testsuite/libamf.all/test_sol.cpp
===================================================================
RCS file: /sources/gnash/gnash/testsuite/libamf.all/test_sol.cpp,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -b -r1.13 -r1.14
--- testsuite/libamf.all/test_sol.cpp 30 Apr 2008 03:35:31 -0000 1.13
+++ testsuite/libamf.all/test_sol.cpp 16 May 2008 03:46:34 -0000 1.14
@@ -187,6 +187,8 @@
GNASH_REPORT_FUNCTION;
struct stat st;
+ Buffer *hex1 = hex2mem("00 bf 00 00 01 28 54 43 53 4f 00 04 00 00 00 00 00
08 73 65 74 74 69 6e 67 73 00 00 00 00 00 04 67 61 69 6e 00 40 49 00 00 00 00
00 00 00 00 0f 65 63 68 6f 73 75 70 70 72 65 73 73 69 6f 6e 01 00 00 00 11 64
65 66 61 75 6c 74 6d 69 63 72 6f 70 68 6f 6e 65 02 00 0e 2f 64 65 76 2f 69 6e
70 75 74 2f 6d 69 63 00 00 0d 64 65 66 61 75 6c 74 63 61 6d 65 72 61 02 00 00
00 00 0d 64 65 66 61 75 6c 74 6b 6c 69 6d 69 74 00 40 59 00 00 00 00 00 00 00
00 0d 64 65 66 61 75 6c 74 61 6c 77 61 79 73 01 00 00 00 10 63 72 6f 73 73 64
6f 6d 61 69 6e 41 6c 6c 6f 77 01 01 00 00 11 63 72 6f 73 73 64 6f 6d 61 69 6e
41 6c 77 61 79 73 01 01 00 00 18 61 6c 6c 6f 77 54 68 69 72 64 50 61 72 74 79
4c 53 4f 41 63 63 65 73 73 01 01 00 00 0c 74 72 75 73 74 65 64 50 61 74 68 73
03 00 00 09 00 00 0c 6c 6f 63 61 6c 53 65 63 50 61 74 68 02 00 00 00 00 10 6c
6f 63 61 6c 53 65 63 50 61 74 68 54 69 6d 65 00 42 71 6d 14 10 22 e0 00 00");
+
if (stat(filespec.c_str(), &st) == 0) {
SOL sol;
sol.readFile(filespec);
Index: testsuite/libnet.all/test_cque.cpp
===================================================================
RCS file: /sources/gnash/gnash/testsuite/libnet.all/test_cque.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- testsuite/libnet.all/test_cque.cpp 7 Apr 2008 19:35:11 -0000 1.4
+++ testsuite/libnet.all/test_cque.cpp 16 May 2008 03:46:35 -0000 1.5
@@ -73,8 +73,8 @@
ptr[i] = i+' ';
}
- boost::uint8_t *test = new uint8_t[6];
- memcpy(test, "hell", 4);
+// boost::uint8_t *test = new uint8_t[6];
+// memcpy(test, "hell", 4);
// Push one buffer on the fifo. The default is the incoming fifo,
// which is the one where data flows from the network to the queue.
Index: testsuite/libnet.all/test_handler.cpp
===================================================================
RCS file: /sources/gnash/gnash/testsuite/libnet.all/test_handler.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- testsuite/libnet.all/test_handler.cpp 6 Apr 2008 18:11:33 -0000
1.3
+++ testsuite/libnet.all/test_handler.cpp 16 May 2008 03:46:38 -0000
1.4
@@ -66,8 +66,8 @@
Handler que;
Buffer buf;
- boost::uint8_t *test = new uint8_t[6];
- memcpy(test, "hell", 4);
+// boost::uint8_t *test = new uint8_t[6];
+// memcpy(test, "hell", 4);
// Push one buffer on the fifo. The default is the incoming fifo,
// which is the one where data flows from the network to the queue.
Index: testsuite/libnet.all/test_rtmp.cpp
===================================================================
RCS file: /sources/gnash/gnash/testsuite/libnet.all/test_rtmp.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- testsuite/libnet.all/test_rtmp.cpp 3 May 2008 18:44:06 -0000 1.1
+++ testsuite/libnet.all/test_rtmp.cpp 16 May 2008 03:46:38 -0000 1.2
@@ -36,8 +36,9 @@
#include "dejagnu.h"
#include "log.h"
#include "amf.h"
-#include "rtmp_server.h"
#include "rtmp.h"
+#include "rtmp_client.h"
+#include "rtmp_server.h"
#include "buffer.h"
#include "network.h"
#include "element.h"
@@ -65,6 +66,8 @@
static void test_header();
static void test_types();
+static void test_results();
+static void test_system();
LogFile& dbglogfile = LogFile::getDefaultInstance();
@@ -96,7 +99,7 @@
{
size_t count = strlen(str);
Network::byte_t ch = 0;
- Buffer *buf = new Buffer(count + 12);
+ Buffer *buf = new Buffer((count/3)+1);
buf->clear();
Network::byte_t *ptr = const_cast<Network::byte_t
*>(reinterpret_cast<const Network::byte_t *>(str));
@@ -168,68 +171,294 @@
#endif
test_header();
- test_types();
+ test_system();
+ test_results();
+// test_types();
+}
+
+void
+test_system()
+{
+ GNASH_REPORT_FUNCTION;
+
+ RTMPClient client;
+ RTMPServer server;
+
+
+// const char *x1 = "00 00 00 00 00 00";
+ Buffer *buf1 = hex2mem("00 00 00 00 00 00"); // clear buffer message
+// const char *x2 = "00 06 cf 03 04 c3";
+ Buffer *buf2 = hex2mem("00 06 cf 03 04 c3"); // ping client from server
+// const char *x3 = "00 07 cf 03 04 c3";
+ Buffer *buf3 = hex2mem("00 07 cf 03 04 c3"); // Pong, reply from client
+// const char *x4 = "00 00 00 00 00 01";
+ Buffer *buf4 = hex2mem("00 00 00 00 00 01"); // clear buffer message
+
+ RTMP::rtmp_ping_t *ping1 = client.decodePing(buf1);
+ if (ping1->type == RTMP::PING_CLEAR) {
+ runtest.pass("Decoded RTMP Ping message");
+ } else {
+ runtest.fail("Decoded RTMP Ping message");
+ }
+
+ Buffer *enc1 = server.encodePing(RTMP::PING_CLEAR);
+ if ((memcmp(buf1->reference(), enc1->reference(), 6) == 0)) {
+ runtest.pass("Encoded RTMP Ping Clear message");
+ } else {
+ runtest.fail("Encoded RTMP Ping Clear message");
+ }
+
+ boost::uint32_t time = *(reinterpret_cast<boost::uint32_t
*>(buf2->reference() + 2));
+ Buffer *enc2 = server.encodePing(RTMP::PING_CLIENT, htonl(time));
+// cerr << hexify(enc2->begin(), enc2->size(), false) << endl;
+ if ((memcmp(buf2->reference(), enc2->reference(), 6) == 0)) {
+ runtest.pass("Encoded RTMP Ping Client message");
+ } else {
+ runtest.fail("Encoded RTMP Ping Client message");
+ }
+
+ RTMP::rtmp_ping_t *ping2 = client.decodePing(buf2);
+ if ((ping2->type == RTMP::PING_CLIENT)
+ && (ping2->target == 0xcf03)
+ && (ping2->param1 == 0x4c3)) {
+ runtest.pass("Decoded RTMP Ping Client message");
+ } else {
+ runtest.fail("Decoded RTMP Ping Client message");
+ }
+
+#if 0
+ for (double dub=0; dub<=200; dub ++) {
+ Element el11;
+ el11.makeNumber(dub);
+ Buffer *buf11 = el11.getBuffer();
+ cerr << "FIXME: " << el11.to_number() << ": ";
+ swapBytes(buf11->begin(), 8);
+ cerr << hexify(buf11->begin(), buf11->size(), false) << endl;
+ }
+#endif
+
+ // cleanup
+ delete ping1;
+ delete ping2;
+ delete buf1;
+ delete buf2;
+ delete buf3;
+ delete buf4;
+
+ delete enc1;
+ delete enc2;
}
void
test_header()
{
GNASH_REPORT_FUNCTION;
- RTMP rtmp;
+ RTMPClient client;
+ RTMPServer server;
// this is a sample 12 bytes RTMP header
- const char *x = "03 00 00 00 00 01 1f 14 00 00 00 00";
- Buffer *buf1 = hex2mem(x);
- Buffer *head = rtmp.encodeHeader(0x3, RTMP::HEADER_12, 287,
- RTMP::INVOKE, RTMP::FROM_CLIENT);
-// cerr << hexify(head->begin(), 12, false) << endl;
+// const char *x1 = "03 00 00 00 00 01 1f 14 00 00 00 00";
+ Buffer *buf1 = hex2mem("03 00 00 00 00 01 1f 14 00 00 00 00");
+ Buffer *head1 = server.encodeHeader(0x3, RTMP::HEADER_12, 287,
+ RTMP::INVOKE, RTMPMsg::FROM_SERVER);
+// cerr << hexify(head1->begin(), RTMP_MAX_HEADER_SIZE, false) << endl;
+
+ if ((memcmp(buf1->reference(), head1->reference(), RTMP_MAX_HEADER_SIZE)
== 0)) {
+ runtest.pass("Encoded RTMP header(Invoke)");
+ } else {
+ runtest.fail("Encoded RTMP header(Invoke)");
+ }
+
+ RTMP::rtmp_head_t *header1 = server.decodeHeader(buf1->reference());
+ if ((header1->channel == 0x3) && (header1->head_size ==
RTMP_MAX_HEADER_SIZE)
+ && (header1->bodysize == 287) && (header1->type == RTMP::INVOKE)) {
+ runtest.pass("Decoded RTMP header(Invoke)");
+ } else {
+ runtest.fail("Decoded RTMP header(Invoke)");
+ }
+
+ Buffer *buf2 = hex2mem("02 00 00 00 00 00 06 04 00 00 00 00");
+ Buffer *head2 = server.encodeHeader(0x2, RTMP::HEADER_12, PING_MSG_SIZE,
+ RTMP::PING, RTMPMsg::FROM_SERVER);
+// cerr << hexify(head2->begin(), RTMP_MAX_HEADER_SIZE, false) << endl;
+ if ((memcmp(buf2->reference(), head2->reference(), 8) == 0)) {
+ runtest.pass("Encoded RTMP header(Ping 0)");
+ } else {
+ runtest.fail("Encoded RTMP header(Ping 0)");
+ }
+
+ Buffer *buf3 = hex2mem("02 ff e3 6c 00 00 06 04 00 00 00 00");
+ Buffer *head3 = server.encodeHeader(0x2, RTMP::HEADER_12, PING_MSG_SIZE,
+ RTMP::PING, RTMPMsg::FROM_SERVER);
+// cerr << hexify(head3->begin(), RTMP_MAX_HEADER_SIZE, false) << endl;
+ if ((memcmp(buf2->reference(), head3->reference(), 8) == 0)) {
+ runtest.pass("Encoded RTMP header(Ping 1)");
+ } else {
+ runtest.fail("Encoded RTMP header(Ping 1)");
+ }
- if ((memcmp(buf1->reference(), head->reference(), 12) == 0)) {
- runtest.pass("Encoded RTMP header");
+ RTMP::rtmp_head_t *header2 = client.decodeHeader(buf3);
+ if ((header2->channel == 0x2) && (header2->head_size ==
RTMP_MAX_HEADER_SIZE)
+ && (header2->bodysize == 6) && (header2->type == RTMP::PING)) {
+ runtest.pass("Decoded RTMP header(Ping)");
} else {
- runtest.fail("Encoded RTMP header");
+ runtest.fail("Decoded RTMP header(Ping)");
}
- RTMP::rtmp_head_t *header = rtmp.decodeHeader(buf1->reference());
- if ((header->channel == 0x3) && (header->head_size == 12)
- && (header->bodysize == 287) && (header->type == RTMP::INVOKE)) {
- runtest.pass("Decoded RTMP header");
+ Buffer *buf4 = hex2mem("c2");
+ Buffer *head4 = server.encodeHeader(0x2, RTMP::HEADER_1);
+// cerr << hexify(head4->begin(), RTMP_MAX_HEADER_SIZE, false) << endl;
+ if ((memcmp(buf4->reference(), head4->reference(), 1) == 0)) {
+ runtest.pass("Encoded RTMP header(size 1)");
} else {
- runtest.fail("Decoded RTMP header");
+ runtest.fail("Encoded RTMP header(size 1)");
}
// cleanup after ourselves
delete buf1;
- delete head;
+ delete buf2;
+ delete buf3;
+ delete buf4;
+ delete head1;
+ delete head2;
+ delete head3;
+ delete head4;
+// delete header1;
+// delete header2;
}
-
void
-test_types()
+test_results()
{
GNASH_REPORT_FUNCTION;
- RTMP rtmp;
+ RTMPServer rtmpserv;
+// 03 00 00 00 00 00 81 14 00 00 00 00 02 00 07 5f ..............._
+// 72 65 73 75 6c 74 00 3f f0 00 00 00 00 00 00 05 result.?........
+// 03 00 0b 61 70 70 6c 69 63 61 74 69 6f 6e 05 00 ...application..
+// 05 6c 65 76 65 6c 02 00 06 73 74 61 74 75 73 00 .level...status.
+// 0b 64 65 73 63 72 69 70 74 69 6f 6e 02 00 15 43 .description...C
+// 6f 6e 6e 65 63 74 69 6f 6e 20 73 75 63 63 65 65 onnection succee
+// 64 65 64 2e 00 04 63 6f 64 65 02 00 1d 4e 65 74 ded...code...Net
+// 43 6f 6e 6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 Connection.Conne
+// 63 74 2e 53 75 63 63 65 73 73 00 00 c3 09 ct.Success....
+ Buffer *hex2 = hex2mem("02 00 07 5f 72 65 73 75 6c 74 00 3f f0 00 00 00 00
00 00 05 03 00 0b 61 70 70 6c 69 63 61 74 69 6f 6e 05 00 05 6c 65 76 65 6c 02
00 06 73 74 61 74 75 73 00 0b 64 65 73 63 72 69 70 74 69 6f 6e 02 00 15 43 6f
6e 6e 65 63 74 69 6f 6e 20 73 75 63 63 65 65 64 65 64 2e 00 04 63 6f 64 65 02
00 1d 4e 65 74 43 6f 6e 6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 63 74 2e 53 75
63 63 65 73 73 00 00 09");
+
+ RTMPMsg *msg1 = rtmpserv.decodeMsgBody(hex2);
+ if (msg1) {
+ std::vector<amf::Element *> hell = msg1->getElements();
+ std::vector<amf::Element *> props = hell[0]->getProperties();
+// printf("FIXME: %d, %d, %s:%s\n", props.size(), msg1->getStatus(),
+// props[3]->getName(), props[3]->to_string());
+// msg1->dump();
+ if ((msg1->getStatus() == RTMPMsg::NC_CONNECT_SUCCESS)
+ && (msg1->getMethodName() == "_result")
+ && (msg1->getStreamID() == 1)
+ && (msg1->size() == 1)) { // the msg has one element, which has 4
properties
+ runtest.pass("Decoded RTMP Result(NC_CONNECT_SUCCESS) message");
+ } else {
+ runtest.fail("Decoded RTMP Result(NC_CONNECT_SUCCESS) message");
+ }
+ } else {
+ runtest.untested("Decoded RTMP Result(NC_CONNECT_SUCCESS) message");
+ }
+ delete msg1;
- const char *x = "06 00 d2 04 00 00 00 00";
- Buffer *buf1 = hex2mem(x);
+ Buffer *buf2 = rtmpserv.encodeResult(RTMPMsg::NC_CONNECT_SUCCESS);
+// cerr << hexify(buf2->begin(), 122, true) << endl;
+ if ((memcmp(hex2->reference(), buf2->reference(), 122) == 0)) {
+ runtest.pass("Encoded RTMP result(NC_CONNECT_SUCCESS)");
+ } else {
+ runtest.fail("Encoded RTMP result(NC_CONNECT_SUCCESS)");
+ }
+ delete buf2;
+ delete hex2;
- RTMP::rtmp_ping_t *ping = rtmp.decodePing(buf1);
- if (ping->type == RTMP::PING_CLIENT) {
- runtest.pass("Decoded RTMP Ping message");
+ Buffer *hex3 = hex2mem("02 00 07 5f 72 65 73 75 6c 74 00 3f f0 00 00 00 00
00 00 05 03 00 0b 61 70 70 6c 69 63 61 74 69 6f 6e 05 00 05 6c 65 76 65 6c 02
00 05 65 72 72 6f 72 00 0b 64 65 73 63 72 69 70 74 69 6f 6e 02 00 00 00 04 63
6f 64 65 02 00 1c 4e 65 74 43 6f 6e 6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 63
74 2e 46 61 69 6c 65 64 00 00 09");
+ RTMPMsg *msg2 = rtmpserv.decodeMsgBody(hex3);
+ std::vector<amf::Element *> hell = msg2->getElements();
+ std::vector<amf::Element *> props = hell[0]->getProperties();
+// printf("FIXME: %d, %d, %s:%s\n", props.size(), msg1->getStatus(),
+// props[3]->getName(), props[3]->to_string());
+ if (msg2) {
+// msg2->dump();
+ if ((msg2->getStatus() == RTMPMsg::NC_CONNECT_FAILED)
+ && (msg2->getMethodName() == "_result")
+ && (msg2->getStreamID() == 1)
+ && (msg2->size() == 1)) {
+ runtest.pass("Decoded RTMP result(NC_CONNECT_FAILED(as result)");
} else {
- runtest.fail("Decoded RTMP Ping message");
+ runtest.fail("Decoded RTMP result(NC_CONNECT_FAILED(as result)");
}
+ } else {
+ runtest.untested("Decoded RTMP result(NC_CONNECT_FAILED(as result)");
+ }
+
+ delete msg2;
- Buffer *buf2 = rtmp.encodePing(RTMP::PING_CLIENT, 53764);
- cerr << hexify(buf2->begin(), 8, false) << endl;
- if ((memcmp(buf1->reference(), buf2->reference(), 8) == 0)) {
- runtest.pass("Encoded RTMP Ping message");
+ delete hex3;
+
+// Buffer hex4 = "43 00 00 00 00 00 48 14 02 00 06 5f 65 72 72 6f 72 00 40
00 00 00 00 00 00 00 05 03 00 04 63 6f 64 65 02 00 19 4e 65 74 43 6f 6e 6e 65
63 74 69 6f 6e 2e 43 61 6c 6c 2e 46 61 69 6c 65 64 00 05 6c 65 76 65 6c 02 00
05 65 72 72 6f 72 00 00 09";
+// if ((memcmp(hex4->reference(), buf4->reference(), hex4->size()) == 0)) {
+// runtest.pass("Encoded RTMP result(NC_CONNECT_FAILED(as result)");
+// } else {
+// runtest.fail("Encoded RTMP result(NC_CONNECT_FAILED(as result)");
+// }
+// delete buf4;
+
+
+#if 0
+// const char *x4 = "";
+ Buffer *hex4 = hex2mem("");
+ Buffer *buf4 = rtmpserv.encodeResult(RTMPMsg::NC_CONNECT_REJECTED);
+ if ((memcmp(hex4->reference(), buf4->reference(), buf4->size()) == 0)) {
+ runtest.pass("Encoded RTMP result(NC_CONNECT_REJECTED");
} else {
- runtest.fail("Encoded RTMP Ping message");
+ runtest.fail("Encoded RTMP result(NC_CONNECT_REJECTED)");
}
- delete ping;
- delete buf1;
- delete buf2;
+ delete buf4;
+
+// const char *x5 = "";
+ Buffer *hex5 = hex2mem("");
+ Buffer *buf5 = rtmpserv.encodeResult(RTMPMsg::NC_CONNECT_APPSHUTDOWN);
+ if ((memcmp(hex5->reference(), buf5->reference(), buf5->size()) == 0)) {
+ runtest.pass("Encoded RTMP result(NC_CONNECT_APPSHUTDOWN)");
+ } else {
+ runtest.fail("Encoded RTMP result(NC_CONNECT_APPSHUTDOWN)");
+ }
+ delete buf5;
+
+// const char *x6 = "";
+ Buffer *hex6 = hex2mem("");
+ Buffer *buf6 =
rtmpserv.encodeResult(RTMPMsg::NC_CONNECT_INVALID_APPLICATION);
+ if ((memcmp(hex6->reference(), buf6->reference(), buf6->size()) == 0)) {
+ runtest.pass("Encoded RTMP result(NC_CONNECT_INVALID_APPLICATION)");
+ } else {
+ runtest.fail("Encoded RTMP result(NC_CONNECT_INVALID_APPLICATION)");
+ }
+ delete buf6;
+
+// const char *x7 = "";
+ Buffer *hex7 = hex2mem("");
+ Buffer *buf7 = rtmpserv.encodeResult(RTMPMsg::NC_CONNECT_CLOSED);
+ if ((memcmp(hex7->reference(), buf7->reference(), buf7->size()) == 0)) {
+ runtest.pass("Encoded RTMP result(NC_CONNECT_INVALID_CLOSED)");
+ } else {
+ runtest.fail("Encoded RTMP result(NC_CONNECT_INVALID_CLOSED)");
+ }
+ delete buf7;
+#endif
+
+}
+
+void
+test_types()
+{
+ GNASH_REPORT_FUNCTION;
+ RTMP rtmp;
+
+ const char *x = "06 00 d2 04 00 00 00 00";
+ Buffer *buf1 = hex2mem(x);
+
}
static void
Index: libnet/rtmp_client.cpp
===================================================================
RCS file: libnet/rtmp_client.cpp
diff -N libnet/rtmp_client.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libnet/rtmp_client.cpp 16 May 2008 03:46:27 -0000 1.1
@@ -0,0 +1,277 @@
+// rtmp.cpp: Adobe/Macromedia Real Time Message Protocol handler, for Gnash.
+//
+// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <iostream>
+#include <string>
+#include <map>
+
+#if ! (defined(_WIN32) || defined(WIN32))
+# include <netinet/in.h>
+#endif
+
+#include "log.h"
+#include "rc.h"
+#include "amf.h"
+#include "rtmp.h"
+#include "rtmp_client.h"
+#include "network.h"
+#include "element.h"
+#include "handler.h"
+#include "utility.h"
+#include "buffer.h"
+
+using namespace gnash;
+using namespace std;
+using namespace amf;
+
+namespace gnash
+{
+
+// The rcfile is loaded and parsed here:
+static RcInitFile& rcfile = RcInitFile::getDefaultInstance();
+
+extern map<int, Handler *> handlers;
+
+RTMPClient::RTMPClient()
+ : _connections(0)
+{
+// GNASH_REPORT_FUNCTION;
+}
+
+RTMPClient::~RTMPClient()
+{
+// GNASH_REPORT_FUNCTION;
+ _variables.clear();
+// delete _body;
+}
+
+
+// These are used for creating the primary objects
+
+// Make the NetConnection object that is used to connect to the
+// server.
+amf::Buffer *
+RTMPClient::encodeConnect(const char *app, const char *swfUrl, const char
*tcUrl,
+ double audioCodecs, double videoCodecs, double
videoFunction,
+ const char *pageUrl)
+{
+ GNASH_REPORT_FUNCTION;
+
+ AMF amf_obj;
+
+ Element *connect = new Element;
+ connect->makeString("connect");
+
+ Element *connum = new Element;
+// const char *connumStr = "00 00 00 00 00 00 f0 3f";
+// Buffer *connumBuf = hex2mem(connumStr);
+ // update the counter for the number of connections. This number is used
heavily
+ // in RTMP to help keep communications clear when there are multiple
streams.
+ _connections++;
+ connum->makeNumber(_connections);
+
+ // Make the top level object
+ Element obj;
+ obj.makeObject();
+
+ Element *appnode = new Element;
+ appnode->makeString("app", app);
+ obj.addProperty(appnode);
+
+ const char *version = 0;
+ if (rcfile.getFlashVersionString().size() > 0) {
+ version = rcfile.getFlashVersionString().c_str();
+ } else {
+ version = "LNX 9,0,31,0";
+ }
+
+ Element *flashVer = new Element;
+ flashVer->makeString("flashVer", "LNX 9,0,31,0");
+ obj.addProperty(flashVer);
+
+ Element *swfUrlnode = new Element;
+// swfUrl->makeString("swfUrl",
"http://192.168.1.70/software/gnash/tests/ofla_demo.swf");
+ swfUrlnode->makeString("swfUrl", swfUrl);
+ obj.addProperty(swfUrlnode);
+
+// filespec = "rtmp://localhost/oflaDemo";
+ Element *tcUrlnode = new Element;
+ tcUrlnode->makeString("tcUrl", tcUrl);
+ obj.addProperty(tcUrlnode);
+
+ Element *fpad = new Element;
+ fpad->makeBoolean("fpad", false);
+ obj.addProperty(fpad);
+
+ Element *audioCodecsnode = new Element;
+// audioCodecsnode->makeNumber("audioCodecs", 615);
+ audioCodecsnode->makeNumber("audioCodecs", audioCodecs);
+ obj.addProperty(audioCodecsnode);
+
+ Element *videoCodecsnode = new Element;
+// videoCodecsnode->makeNumber("videoCodecs", 124);
+ videoCodecsnode->makeNumber("videoCodecs", videoCodecs);
+ obj.addProperty(videoCodecsnode);
+
+ Element *videoFunctionnode = new Element;
+// videoFunctionnode->makeNumber("videoFunction", 0x1);
+ videoFunctionnode->makeNumber("videoFunction", videoFunction);
+ obj.addProperty(videoFunctionnode);
+
+ Element *pageUrlnode = new Element;
+// pageUrlnode->makeString("pageUrl",
"http://x86-ubuntu/software/gnash/tests/");
+ pageUrlnode->makeString("pageUrl", pageUrl);
+ obj.addProperty(pageUrlnode);
+
+// size_t total_size = 227;
+// Buffer *out = encodeHeader(0x3, RTMP::HEADER_12, total_size,
+// RTMP::INVOKE, RTMP::FROM_CLIENT);
+// const char *rtmpStr = "03 00 00 04 00 01 1f 14 00 00 00 00";
+// Buffer *rtmpBuf = hex2mem(rtmpStr);
+ Buffer *conobj = connect->encode();
+ Buffer *numobj = connum->encode();
+ Buffer *encobj = obj.encode();
+
+ Buffer *buf = new Buffer(conobj->size() + numobj->size() + encobj->size());
+// buf->append(out);
+ buf->append(conobj);
+ buf->append(numobj);
+ buf->append(encobj);
+
+ return buf;
+}
+
+// 43 00 1a 21 00 00 19 14 02 00 0c 63 72 65 61 74 C..!.......creat
+// 65 53 74 72 65 61 6d 00 40 08 00 00 00 00 00 00 address@hidden
+// 05 .
+amf::Buffer *
+RTMPClient::encodeStream(double /* id */)
+{
+ GNASH_REPORT_FUNCTION;
+
+ struct timespec now;
+ clock_gettime (CLOCK_REALTIME, &now);
+
+// log_debug("Buffer %x (%d) stayed in queue for %f seconds",
+// (void *)_ptr, _nbytes,
+// (float)((now.tv_sec - _stamp.tv_sec) + ((now.tv_nsec -
_stamp.tv_nsec)/1e9)));
+
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
+}
+
+// 127.0.0.1:38167 -> 127.0.0.1:1935 [AP]
+// 08 00 1b 1b 00 00 2a 14 01 00 00 00 02 00 04 70 ......*........p
+// 6c 61 79 00 00 00 00 00 00 00 00 00 05 02 00 16 lay.............
+// 6f 6e 32 5f 66 6c 61 73 68 38 5f 77 5f 61 75 64 on2_flash8_w_aud
+// 69 6f 2e 66 6c 76 c2 00 03 00 00 00 01 00 00 27 io.flv.........'
+// 10
+amf::Buffer *
+RTMPClient::encodePublish()
+{
+ GNASH_REPORT_FUNCTION;
+ log_unimpl(__PRETTY_FUNCTION__);
+ return 0;
+}
+
+// A request for a handshake is initiated by sending a byte with a
+// value of 0x3, followed by a message body of unknown format.
+bool
+RTMPClient::handShakeRequest()
+{
+ GNASH_REPORT_FUNCTION;
+
+#if 0
+ char buffer[RTMP_BODY_SIZE+1];
+ char c = 0x3;
+ int i, ret;
+
+ ret = writeNet(&c, 1);
+ _outbytes += 1;
+ // something went wrong, chances are the other end of the network
+ // connection is down, or never initialized.
+ if (ret <= 0) {
+ return false;
+ }
+
+ // Since we don't know what the format is, create a pattern we can
+ // recognize if we stumble across it later on.
+ for (i=0; i<RTMP_BODY_SIZE; i++) {
+ buffer[i] = i^256;
+ }
+
+ _outbytes += RTMP_BODY_SIZE;
+ ret = writeNet(buffer, RTMP_BODY_SIZE);
+#endif
+
+ return true;
+}
+
+// The client finished the handshake process by sending the second
+// data block we get from the server as the response
+bool
+RTMPClient::clientFinish()
+{
+ GNASH_REPORT_FUNCTION;
+
+#if 0
+ char buffer[RTMP_BODY_SIZE+1];
+ memset(buffer, 0, RTMP_BODY_SIZE+1);
+
+ if (readNet(buffer, RTMP_BODY_SIZE) == RTMP_BODY_SIZE) {
+ log_debug (_("Read first data block in handshake"));
+ } else {
+ log_error (_("Couldn't read first data block in handshake"));
+ return false;
+ }
+ _inbytes += RTMP_BODY_SIZE;
+ if (readNet(buffer, RTMP_BODY_SIZE) == RTMP_BODY_SIZE) {
+ log_debug (_("Read second data block in handshake"));
+// _body = new char(RTMP_BODY_SIZE+1);
+// memcpy(_body, buffer, RTMP_BODY_SIZE);
+ } else {
+ log_error (_("Couldn't read second data block in handshake"));
+ return false;
+ }
+ _inbytes += RTMP_BODY_SIZE;
+
+ writeNet(buffer, RTMP_BODY_SIZE);
+ _outbytes += RTMP_BODY_SIZE;
+#endif
+
+ return true;
+}
+
+// bool
+// RTMPClient::packetRequest()
+// {
+// GNASH_REPORT_FUNCTION;
+// return false;
+// }
+
+} // end of gnash namespace
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
Index: libnet/rtmp_client.h
===================================================================
RCS file: libnet/rtmp_client.h
diff -N libnet/rtmp_client.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libnet/rtmp_client.h 16 May 2008 03:46:27 -0000 1.1
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2008 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _RTMP_CLIENT_H_
+#define _RTMP_CLIENT_H_ 1
+
+#include <boost/cstdint.hpp>
+#include <string>
+#include <map>
+#include <time.h>
+
+#include "rtmp.h"
+#include "amf.h"
+#include "element.h"
+#include "handler.h"
+#include "network.h"
+#include "buffer.h"
+
+namespace gnash
+{
+
+class DSOEXPORT RTMPClient : public RTMP
+{
+public:
+ RTMPClient();
+ ~RTMPClient();
+
+ bool handShakeWait();
+ bool handShakeResponse();
+ bool clientFinish();
+ bool handShakeRequest();
+
+ // These are used for creating the primary objects
+ // Create the initial object sent to the server, which is
NetConnection::connect()
+ amf::Buffer *encodeConnect(const char *app, const char *swfUrl, const char
*tcUrl,
+ double audioCodecs, double videoCodecs, double
videoFunction,
+ const char *pageUrl);
+ // Create the second object sent to the server, which is
NetStream():;NetStream()
+ amf::Buffer *encodeStream(double id);
+
+ amf::Buffer *encodePublish();
+
+ void dump();
+ private:
+ double _connections;
+};
+
+// This is the thread for all incoming RTMP connections
+void rtmp_handler(Handler::thread_params_t *args);
+
+} // end of gnash namespace
+// end of _RTMP_CLIENT_H_
+#endif
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+
Index: libnet/rtmp_msg.cpp
===================================================================
RCS file: libnet/rtmp_msg.cpp
diff -N libnet/rtmp_msg.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libnet/rtmp_msg.cpp 16 May 2008 03:46:29 -0000 1.1
@@ -0,0 +1,146 @@
+// rtmp.cpp: Adobe/Macromedia Real Time Message Protocol handler, for Gnash.
+//
+// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <iostream>
+#include <string>
+#include <map>
+
+#if ! (defined(_WIN32) || defined(WIN32))
+# include <netinet/in.h>
+#endif
+
+#include "log.h"
+#include "amf.h"
+#include "rtmp.h"
+#include "rtmp_msg.h"
+#include "network.h"
+#include "element.h"
+#include "handler.h"
+#include "utility.h"
+#include "buffer.h"
+
+using namespace gnash;
+using namespace std;
+using namespace amf;
+
+namespace gnash
+{
+
+RTMPMsg::RTMPMsg()
+ : _routing(FROM_SERVER),
+ _status(APP_SHUTDOWN),
+ _streamid(0),
+ _channel(9)
+{
+// GNASH_REPORT_FUNCTION;
+// _inbytes = 0;
+// _outbytes = 0;
+
+// _body = new unsigned char(RTMP_BODY_SIZE+1);
+// memset(_body, 0, RTMP_BODY_SIZE+1);
+}
+
+RTMPMsg::~RTMPMsg()
+{
+// GNASH_REPORT_FUNCTION;
+ vector<amf::Element *>::iterator it;
+ for (it = _amfobjs.begin(); it != _amfobjs.end(); it++) {
+ amf::Element *el = (*(it));
+ if (el) {
+// el->dump();
+ delete el;
+ }
+ }
+
+}
+
+RTMPMsg::rtmp_status_e
+RTMPMsg::checkStatus(amf::Element * /* el */)
+{
+// GNASH_REPORT_FUNCTION;
+ if (_amfobjs.size() > 0) {
+ vector<amf::Element *>::iterator pit;
+ vector<amf::Element *>::iterator cit;
+// cerr << "# of Properties in object" << _amfobjs.size() << endl;
+ for (pit = _amfobjs.begin(); pit != _amfobjs.end(); pit++) {
+ amf::Element *el = (*(pit));
+ std::vector<amf::Element *> props = el->getProperties();
+// printf("FIXME2: %d, %s:%s\n", props.size(),
+// props[2]->getName(), props[2]->to_string());
+ if (el->getType() == Element::OBJECT_AMF0) {
+ for (cit = props.begin(); cit != props.end(); cit++) {
+ amf::Element *child = (*(cit));
+// child->dump();
+ string name = child->getName();
+ string value;
+ if (child->getLength()) {
+ value = child->to_string();
+ if (name == "code") {
+// log_debug("Name is: %s, Value is: %s",
name.c_str(), value.c_str());
+ if (value == "NetConnection.Connect.Success") {
+ _status = RTMPMsg::NC_CONNECT_SUCCESS;
+ return _status;
+ }
+ if (value == "NetConnection.Connect.Failed") {
+ _status = RTMPMsg::NC_CONNECT_FAILED;
+ return _status;
+ }
+ if (value == "NetConnection.Call.Failed") {
+ _status = RTMPMsg::NC_CALL_FAILED;
+ return _status;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _status;
+}
+
+void
+RTMPMsg::dump()
+{
+// GNASH_REPORT_FUNCTION;
+
+// cerr <<"Timestamp: " << _header.timestamp << endl;
+// cerr << "Length: " << _header.length << endl;
+
+ cerr << "Method Name:\t" << _method << endl;
+// cerr << "Stream ID:\t" << hexify((const unsigned char *)&_streamid, 8,
false) << endl;
+ cerr << "Stream ID:\t" << _streamid << endl;
+
+ vector<amf::Element *>::iterator ait;
+ cerr << "# of Elements in file: " << _amfobjs.size() << endl;
+ for (ait = _amfobjs.begin(); ait != _amfobjs.end(); ait++) {
+ amf::Element *el = (*(ait));
+ el->dump();
+ }
+}
+
+} // end of gnash namespace
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
Index: libnet/rtmp_msg.h
===================================================================
RCS file: libnet/rtmp_msg.h
diff -N libnet/rtmp_msg.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libnet/rtmp_msg.h 16 May 2008 03:46:31 -0000 1.1
@@ -0,0 +1,129 @@
+//
+// Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+#ifndef _RTMPMSG_H_
+#define _RTMPMSG_H_
+
+#include <boost/cstdint.hpp>
+#include <string>
+#include <vector>
+
+#include "amf.h"
+#include "rtmp.h"
+#include "element.h"
+#include "handler.h"
+#include "network.h"
+#include "buffer.h"
+
+namespace gnash
+{
+
+class DSOEXPORT RTMPMsg
+{
+public:
+ typedef enum {
+ APP_GC,
+ APP_RESOURCE_LOWMEMORY,
+ APP_SCRIPT_ERROR,
+ APP_SCRIPT_WARNING,
+ APP_SHUTDOWN,
+ NC_CALL_BADVERSION,
+ NC_CALL_FAILED,
+ NC_CONNECT_APPSHUTDOWN,
+ NC_CONNECT_CLOSED,
+ NC_CONNECT_FAILED,
+ NC_CONNECT_INVALID_APPLICATION,
+ NC_CONNECT_REJECTED,
+ NC_CONNECT_SUCCESS,
+ NS_CLEAR_FAILED,
+ NS_CLEAR_SUCCESS,
+ NS_DATA_START,
+ NS_FAILED,
+ NS_INVALID_ARGUMENT,
+ NS_PAUSE_NOTIFY,
+ NS_PLAY_COMPLETE,
+ NS_PLAY_FAILED,
+ NS_PLAY_FILE_STRUCTURE_INVALID,
+ NS_PLAY_INSUFFICIENT_BW,
+ NS_PLAY_NO_SUPPORTED_TRACK_FOUND,
+ NS_PLAY_PUBLISHNOTIFY,
+ NS_PLAY_RESET,
+ NS_PLAY_START,
+ NS_PLAY_STOP,
+ NS_PLAY_STREAMNOTFOUND,
+ NS_PLAY_SWITCH,
+ NS_PLAY_UNPUBLISHNOTIFY,
+ NS_PUBLISH_BADNAME,
+ NS_PUBLISH_START,
+ NS_RECORD_FAILED,
+ NS_RECORD_NOACCESS,
+ NS_RECORD_START,
+ NS_RECORD_STOP,
+ NS_SEEK_FAILED,
+ NS_SEEK_NOTIFY,
+ NS_UNPAUSE_NOTIFY,
+ NS_UNPUBLISHED_SUCCESS,
+ SO_CREATION_FAILED,
+ SO_NO_READ_ACCESS,
+ SO_NO_WRITE_ACCESS,
+ SO_PERSISTENCE_MISMATCH
+ } rtmp_status_e;
+ typedef enum {
+ FROM_SERVER, // Flash com server
+ FROM_CLIENT // Flash player
+ } rtmp_source_e;
+ RTMPMsg();
+ ~RTMPMsg();
+
+ void addObject(amf::Element *el) { _amfobjs.push_back(el); };
+ size_t size() { return _amfobjs.size(); };
+ std::vector<amf::Element *> getElements() { return _amfobjs; };
+
+ void setMethodName(const std::string &name) { _method = name; } ;
+ std::string &getMethodName() { return _method; };
+
+ void setStreamID(double num) { _streamid = num; };
+ double getStreamID() { return _streamid; };
+
+ rtmp_status_e checkStatus(amf::Element *el);
+ void setStatus(rtmp_status_e st) { _status = st; };
+ rtmp_status_e getStatus() { return _status; };
+
+ void setChannel(Network::byte_t num) { _channel = num; };
+ Network::byte_t getChannel() { return _channel; } ;
+
+ // Dump internal status to the terminal
+ void dump();
+
+ protected:
+ rtmp_source_e _routing;
+ rtmp_status_e _status;
+ std::string _method;
+ double _streamid;
+ std::vector<amf::Element *> _amfobjs;
+ Network::byte_t _channel;
+};
+
+} // end of gnash namespace
+// end of _RTMPMSG_H_
+#endif
+
+// local Variables:
+// mode: C++
+// indent-tabs-mode: t
+// End:
+
- [Gnash-commit] gnash ChangeLog libamf/amf.cpp libamf/amf.h lib...,
Rob Savoye <=