From df400ef1c59ab306e4e194cc2c98f35696f648d0 Mon Sep 17 00:00:00 2001 From: winlin Date: Sat, 19 Oct 2013 21:32:41 +0800 Subject: [PATCH] connect vhost/app packet decoded. --- trunk/src/core/srs_core_amf0.cpp | 282 ++++++++++++++++++++++++--- trunk/src/core/srs_core_amf0.hpp | 67 ++++--- trunk/src/core/srs_core_protocol.cpp | 21 +- trunk/src/core/srs_core_protocol.hpp | 1 + trunk/src/core/srs_core_stream.cpp | 7 +- trunk/src/core/srs_core_stream.hpp | 5 + 6 files changed, 324 insertions(+), 59 deletions(-) diff --git a/trunk/src/core/srs_core_amf0.cpp b/trunk/src/core/srs_core_amf0.cpp index 89cd500f5..c9215790d 100755 --- a/trunk/src/core/srs_core_amf0.cpp +++ b/trunk/src/core/srs_core_amf0.cpp @@ -24,6 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #include // AMF0 marker @@ -49,30 +50,34 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // origin array whos data takes the same form as LengthValueBytes #define RTMP_AMF0_OriginStrictArray 0x20 -std::string srs_amf0_read_utf8(SrsStream* stream) +int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*&); + +int srs_amf0_read_utf8(SrsStream* stream, std::string& value) { - std::string str; + int ret = ERROR_SUCCESS; // len if (!stream->require(2)) { - srs_warn("amf0 read string length failed"); - return str; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read string length failed. ret=%d", ret); + return ret; } int16_t len = stream->read_2bytes(); srs_verbose("amf0 read string length success. len=%d", len); // empty string if (len <= 0) { - srs_verbose("amf0 read empty string."); - return str; + srs_verbose("amf0 read empty string. ret=%d", ret); + return ret; } // data if (!stream->require(len)) { - srs_warn("amf0 read string data failed"); - return str; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read string data failed. ret=%d", ret); + return ret; } - str = stream->read_string(len); + std::string str = stream->read_string(len); // support utf8-1 only // 1.3.1 Strings and UTF-8 @@ -80,54 +85,104 @@ std::string srs_amf0_read_utf8(SrsStream* stream) for (int i = 0; i < len; i++) { char ch = *(str.data() + i); if ((ch & 0x80) != 0) { - srs_warn("only support utf8-1, 0x00-0x7F, actual is %#x", (int)ch); - return ""; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("only support utf8-1, 0x00-0x7F, actual is %#x. ret=%d", (int)ch, ret); + return ret; } } + + value = str; srs_verbose("amf0 read string data success. str=%s", str.c_str()); - return str; + return ret; } -std::string srs_amf0_read_string(SrsStream* stream) +int srs_amf0_read_string(SrsStream* stream, std::string& value) { + int ret = ERROR_SUCCESS; + // marker if (!stream->require(1)) { - srs_warn("amf0 read string marker failed"); - return ""; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read string marker failed. ret=%d", ret); + return ret; } char marker = stream->read_char(); if (marker != RTMP_AMF0_String) { - srs_warn("amf0 check string marker failed. marker=%#x, required=%#x", marker, RTMP_AMF0_String); - return ""; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 check string marker failed. " + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_String, ret); + return ret; } srs_verbose("amf0 read string marker success"); - return srs_amf0_read_utf8(stream); + return srs_amf0_read_utf8(stream, value); } -double srs_amf0_read_number(SrsStream* stream) +int srs_amf0_read_boolean(SrsStream* stream, bool& value) { - double value = 0; + int ret = ERROR_SUCCESS; // marker if (!stream->require(1)) { - srs_warn("amf0 read number marker failed"); - return value; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read bool marker failed. ret=%d", ret); + return ret; + } + + char marker = stream->read_char(); + if (marker != RTMP_AMF0_Boolean) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 check bool marker failed. " + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Boolean, ret); + return ret; + } + srs_verbose("amf0 read bool marker success"); + + // value + if (!stream->require(1)) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read bool value failed. ret=%d", ret); + return ret; + } + + if (stream->read_char() == 0) { + value = false; + } else { + value = true; + } + + srs_verbose("amf0 read bool value success. value=%d", value); + + return ret; +} + +int srs_amf0_read_number(SrsStream* stream, double& value) +{ + int ret = ERROR_SUCCESS; + + // marker + if (!stream->require(1)) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read number marker failed. ret=%d", ret); + return ret; } char marker = stream->read_char(); if (marker != RTMP_AMF0_Number) { - srs_warn("amf0 check number marker failed. marker=%#x, required=%#x", marker, RTMP_AMF0_Number); - return value; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 check number marker failed. " + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Number, ret); + return ret; } srs_verbose("amf0 read number marker success"); // value if (!stream->require(8)) { - srs_warn("amf0 read number value failed"); - return value; + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read number value failed. ret=%d", ret); + return ret; } int64_t temp = stream->read_8bytes(); @@ -135,13 +190,158 @@ double srs_amf0_read_number(SrsStream* stream) srs_verbose("amf0 read number value success. value=%.2f", value); - return value; + return ret; } -SrsAmf0Object* srs_amf0_read_object(SrsStream* stream) +int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any*& value) { - SrsAmf0Object* value = NULL; - return value; + int ret = ERROR_SUCCESS; + + // marker + if (!stream->require(1)) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read any marker failed. ret=%d", ret); + return ret; + } + + char marker = stream->read_char(); + srs_verbose("amf0 any marker success"); + + // backward the 1byte marker. + stream->skip(-1); + + switch (marker) { + case RTMP_AMF0_String: { + std::string data; + if ((ret = srs_amf0_read_string(stream, data)) != ERROR_SUCCESS) { + return ret; + } + value = new SrsAmf0String(); + srs_amf0_convert(value)->value = data; + return ret; + } + case RTMP_AMF0_Boolean: { + bool data; + if ((ret = srs_amf0_read_boolean(stream, data)) != ERROR_SUCCESS) { + return ret; + } + value = new SrsAmf0Boolean(); + srs_amf0_convert(value)->value = data; + return ret; + } + case RTMP_AMF0_Number: { + double data; + if ((ret = srs_amf0_read_number(stream, data)) != ERROR_SUCCESS) { + return ret; + } + value = new SrsAmf0Number(); + srs_amf0_convert(value)->value = data; + return ret; + } + case RTMP_AMF0_ObjectEnd: { + SrsAmf0ObjectEOF* p = NULL; + if ((ret = srs_amf0_read_object_eof(stream, p)) != ERROR_SUCCESS) { + return ret; + } + value = p; + return ret; + } + case RTMP_AMF0_Object: { + SrsAmf0Object* p = NULL; + if ((ret = srs_amf0_read_object(stream, p)) != ERROR_SUCCESS) { + return ret; + } + value = p; + return ret; + } + default: + value = new SrsAmf0Any(); + value->marker = stream->read_char(); + return ret; + } + + return ret; +} + +int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*& value) +{ + int ret = ERROR_SUCCESS; + + // marker + if (!stream->require(1)) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read object eof marker failed. ret=%d", ret); + return ret; + } + + char marker = stream->read_char(); + if (marker != RTMP_AMF0_ObjectEnd) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 check object eof marker failed. " + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_ObjectEnd, ret); + return ret; + } + srs_verbose("amf0 read object eof marker success"); + + // value + value = new SrsAmf0ObjectEOF(); + srs_verbose("amf0 read object eof marker success"); + + return ret; +} + +int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value) +{ + int ret = ERROR_SUCCESS; + + // marker + if (!stream->require(1)) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 read object marker failed. ret=%d", ret); + return ret; + } + + char marker = stream->read_char(); + if (marker != RTMP_AMF0_Object) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 check object marker failed. " + "marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret); + return ret; + } + srs_verbose("amf0 read object marker success"); + + // value + value = new SrsAmf0Object(); + + while (!stream->empty()) { + // property-name: utf8 string + std::string property_name; + if ((ret =srs_amf0_read_utf8(stream, property_name)) != ERROR_SUCCESS) { + srs_error("amf0 object read property name failed. ret=%d", ret); + return ret; + } + // property-value: any + SrsAmf0Any* property_value = NULL; + if ((ret = srs_amf0_read_any(stream, property_value)) != ERROR_SUCCESS) { + srs_error("amf0 object read property_value failed. " + "name=%s, ret=%d", property_name.c_str(), ret); + return ret; + } + + // AMF0 Object EOF. + if (property_name.empty() || !property_value || property_value->is_object_eof()) { + if (property_value) { + delete property_value; + } + srs_info("amf0 read object EOF."); + break; + } + + // add property + value->properties[property_name] = property_value; + } + + return ret; } SrsAmf0Any::SrsAmf0Any() @@ -158,6 +358,11 @@ bool SrsAmf0Any::is_string() return marker == RTMP_AMF0_String; } +bool SrsAmf0Any::is_boolean() +{ + return marker == RTMP_AMF0_Boolean; +} + bool SrsAmf0Any::is_number() { return marker == RTMP_AMF0_Number; @@ -168,6 +373,11 @@ bool SrsAmf0Any::is_object() return marker == RTMP_AMF0_Object; } +bool SrsAmf0Any::is_object_eof() +{ + return marker == RTMP_AMF0_ObjectEnd; +} + SrsAmf0String::SrsAmf0String() { marker = RTMP_AMF0_String; @@ -177,6 +387,16 @@ SrsAmf0String::~SrsAmf0String() { } +SrsAmf0Boolean::SrsAmf0Boolean() +{ + marker = RTMP_AMF0_Boolean; + value = false; +} + +SrsAmf0Boolean::~SrsAmf0Boolean() +{ +} + SrsAmf0Number::SrsAmf0Number() { marker = RTMP_AMF0_Number; @@ -185,12 +405,12 @@ SrsAmf0Number::SrsAmf0Number() SrsAmf0Number::~SrsAmf0Number() { + marker = RTMP_AMF0_ObjectEnd; } SrsAmf0ObjectEOF::SrsAmf0ObjectEOF() { utf8_empty = 0x00; - object_end_marker = RTMP_AMF0_ObjectEnd; } SrsAmf0ObjectEOF::~SrsAmf0ObjectEOF() diff --git a/trunk/src/core/srs_core_amf0.hpp b/trunk/src/core/srs_core_amf0.hpp index 8cdd8b1d1..47887994c 100755 --- a/trunk/src/core/srs_core_amf0.hpp +++ b/trunk/src/core/srs_core_amf0.hpp @@ -43,25 +43,30 @@ class SrsAmf0Object; * UTF8-char = UTF8-1 | UTF8-2 | UTF8-3 | UTF8-4 * UTF8-1 = %x00-7F * @remark only support UTF8-1 char. -* @return default value is empty string. */ -extern std::string srs_amf0_read_utf8(SrsStream* stream); +extern int srs_amf0_read_utf8(SrsStream* stream, std::string& value); /** * read amf0 string from stream. * 2.4 String Type * string-type = string-marker UTF-8 -* @return default value is empty string. */ -extern std::string srs_amf0_read_string(SrsStream* stream); +extern int srs_amf0_read_string(SrsStream* stream, std::string& value); + +/** +* read amf0 boolean from stream. +* 2.4 String Type +* boolean-type = boolean-marker U8 +* 0 is false, <> 0 is true +*/ +extern int srs_amf0_read_boolean(SrsStream* stream, bool& value); /** * read amf0 number from stream. * 2.2 Number Type * number-type = number-marker DOUBLE -* @return default value is 0. */ -extern double srs_amf0_read_number(SrsStream* stream); +extern int srs_amf0_read_number(SrsStream* stream, double& value); /** * read amf0 object from stream. @@ -69,7 +74,7 @@ extern double srs_amf0_read_number(SrsStream* stream); * anonymous-object-type = object-marker *(object-property) * object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) */ -extern SrsAmf0Object* srs_amf0_read_object(SrsStream* stream); +extern int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value); /** * any amf0 value. @@ -87,22 +92,10 @@ struct SrsAmf0Any virtual ~SrsAmf0Any(); virtual bool is_string(); + virtual bool is_boolean(); virtual bool is_number(); virtual bool is_object(); - - /** - * convert the any to specified object. - * @return T*, the converted object. never NULL. - * @remark, user must ensure the current object type, - * or the covert will cause assert failed. - */ - template - T* convert() - { - T* p = dynamic_cast(this); - srs_assert(p != NULL); - return p; - } + virtual bool is_object_eof(); }; /** @@ -119,6 +112,21 @@ struct SrsAmf0String : public SrsAmf0Any virtual ~SrsAmf0String(); }; +/** +* read amf0 boolean from stream. +* 2.4 String Type +* boolean-type = boolean-marker U8 +* 0 is false, <> 0 is true +* @return default value is false. +*/ +struct SrsAmf0Boolean : public SrsAmf0Any +{ + bool value; + + SrsAmf0Boolean(); + virtual ~SrsAmf0Boolean(); +}; + /** * read amf0 number from stream. * 2.2 Number Type @@ -138,10 +146,9 @@ struct SrsAmf0Number : public SrsAmf0Any * object-end-type = UTF-8-empty object-end-marker * 0x00 0x00 0x09 */ -struct SrsAmf0ObjectEOF +struct SrsAmf0ObjectEOF : public SrsAmf0Any { int16_t utf8_empty; - char object_end_marker; SrsAmf0ObjectEOF(); virtual ~SrsAmf0ObjectEOF(); @@ -160,5 +167,19 @@ struct SrsAmf0Object : public SrsAmf0Any SrsAmf0Object(); virtual ~SrsAmf0Object(); }; + +/** +* convert the any to specified object. +* @return T*, the converted object. never NULL. +* @remark, user must ensure the current object type, +* or the covert will cause assert failed. +*/ +template +T* srs_amf0_convert(SrsAmf0Any* any) +{ + T* p = dynamic_cast(any); + srs_assert(p != NULL); + return p; +} #endif \ No newline at end of file diff --git a/trunk/src/core/srs_core_protocol.cpp b/trunk/src/core/srs_core_protocol.cpp index ba5f54da3..c521e60c2 100755 --- a/trunk/src/core/srs_core_protocol.cpp +++ b/trunk/src/core/srs_core_protocol.cpp @@ -281,7 +281,11 @@ int SrsMessage::decode_packet() } srs_verbose("decode stream initialized success"); - std::string command = srs_amf0_read_string(stream); + std::string command; + if ((ret = srs_amf0_read_string(stream, command)) != ERROR_SUCCESS) { + srs_error("decode AMF0 command name failed. ret=%d", ret); + return ret; + } srs_verbose("AMF0 command message, command_name=%s", command.c_str()); stream->reset(); @@ -337,7 +341,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream) return ret; } - command_name = srs_amf0_read_string(stream); + if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) { + srs_error("amf0 decode connect command_name failed. ret=%d", ret); + return ret; + } if (command_name.empty() || command_name != RTMP_AMF0_COMMAND_CONNECT) { ret = ERROR_RTMP_AMF0_DECODE; srs_error("amf0 decode connect command_name failed. " @@ -345,7 +352,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream) return ret; } - transaction_id = srs_amf0_read_number(stream); + if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) { + srs_error("amf0 decode connect transaction_id failed. ret=%d", ret); + return ret; + } if (transaction_id != 1.0) { ret = ERROR_RTMP_AMF0_DECODE; srs_error("amf0 decode connect transaction_id failed. " @@ -353,7 +363,10 @@ int SrsConnectAppPacket::decode(SrsStream* stream) return ret; } - command_object = srs_amf0_read_object(stream); + if ((ret = srs_amf0_read_object(stream, command_object)) != ERROR_SUCCESS) { + srs_error("amf0 decode connect command_object failed. ret=%d", ret); + return ret; + } if (command_object == NULL) { ret = ERROR_RTMP_AMF0_DECODE; srs_error("amf0 decode connect command_object failed. ret=%d", ret); diff --git a/trunk/src/core/srs_core_protocol.hpp b/trunk/src/core/srs_core_protocol.hpp index b25ffb5a7..542e5b893 100755 --- a/trunk/src/core/srs_core_protocol.hpp +++ b/trunk/src/core/srs_core_protocol.hpp @@ -238,6 +238,7 @@ public: *pmsg = msg; *ppacket = pkt; + break; } return ret; diff --git a/trunk/src/core/srs_core_stream.cpp b/trunk/src/core/srs_core_stream.cpp index eb9066a3c..06bb9f8bd 100755 --- a/trunk/src/core/srs_core_stream.cpp +++ b/trunk/src/core/srs_core_stream.cpp @@ -70,7 +70,12 @@ bool SrsStream::empty() bool SrsStream::require(int required_size) { - return !empty() && (required_size < bytes + size - p); + return !empty() && (required_size <= bytes + size - p); +} + +void SrsStream::skip(int size) +{ + p += size; } char SrsStream::read_char() diff --git a/trunk/src/core/srs_core_stream.hpp b/trunk/src/core/srs_core_stream.hpp index 5206e5045..320118d68 100755 --- a/trunk/src/core/srs_core_stream.hpp +++ b/trunk/src/core/srs_core_stream.hpp @@ -65,6 +65,11 @@ public: * @return true if stream can read/write specified required_size bytes. */ virtual bool require(int required_size); + /** + * to skip some size. + * @size can be any value. positive to forward; nagetive to backward. + */ + virtual void skip(int size); public: /** * get 1bytes char from stream.