mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	for #250, rename rtmp to protocol dir.
This commit is contained in:
		
							parent
							
								
									d8c7267cfc
								
							
						
					
					
						commit
						a4ba40952a
					
				
					 47 changed files with 174 additions and 174 deletions
				
			
		
							
								
								
									
										1894
									
								
								trunk/src/protocol/srs_rtmp_amf0.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1894
									
								
								trunk/src/protocol/srs_rtmp_amf0.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										840
									
								
								trunk/src/protocol/srs_rtmp_amf0.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										840
									
								
								trunk/src/protocol/srs_rtmp_amf0.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,840 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_RTMP_PROTOCOL_AMF0_HPP | ||||
| #define SRS_RTMP_PROTOCOL_AMF0_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_amf0.hpp> | ||||
| */ | ||||
| 
 | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| 
 | ||||
| class SrsStream; | ||||
| class SrsAmf0Object; | ||||
| class SrsAmf0EcmaArray; | ||||
| class SrsAmf0StrictArray; | ||||
| 
 | ||||
| // internal objects, user should never use it.
 | ||||
| namespace _srs_internal | ||||
| { | ||||
|     class SrsUnSortedHashtable; | ||||
|     class SrsAmf0ObjectEOF; | ||||
|     class SrsAmf0Date; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| Usages: | ||||
| 
 | ||||
| 1. the bytes proxy: SrsStream | ||||
|     // when we got some bytes from file or network,
 | ||||
|     // use SrsStream proxy to read/write bytes
 | ||||
|      | ||||
|     // for example, read bytes from file or network.
 | ||||
|     char* bytes = ...;  | ||||
|      | ||||
|     // initialize the stream, proxy for bytes.
 | ||||
|     SrsStream stream; | ||||
|     stream.initialize(bytes); | ||||
|      | ||||
|     // use stream instead.
 | ||||
| 
 | ||||
| 2. directly read AMF0 any instance from stream: | ||||
|     SrsAmf0Any* pany = NULL; | ||||
|     srs_amf0_read_any(&stream, &pany); | ||||
| 
 | ||||
| 3. use SrsAmf0Any to discovery instance from stream: | ||||
|     SrsAmf0Any* pany = NULL; | ||||
|     SrsAmf0Any::discovery(&stream, &pany); | ||||
| 
 | ||||
| 4. directly read specified AMF0 instance value from stream: | ||||
|     string value; | ||||
|     srs_amf0_read_string(&stream, value); | ||||
|      | ||||
| 5. directly read specified AMF0 instance from stream: | ||||
|     SrsAmf0Any* str = SrsAmf0Any::str(); | ||||
|     str->read(&stream); | ||||
| 
 | ||||
| 6. get value from AMF0 instance: | ||||
|     // parse or set by other user
 | ||||
|     SrsAmf0Any* any = ...; | ||||
|      | ||||
|     if (any->is_string()) { | ||||
|         string str = any->to_string(); | ||||
|     } | ||||
| 
 | ||||
| 7. get complex object from AMF0 insance: | ||||
|     // parse or set by other user
 | ||||
|     SrsAmf0Any* any = ...; | ||||
|      | ||||
|     if (any->is_object()) { | ||||
|         SrsAmf0Object* obj = any->to_object(); | ||||
|         obj->set("width", SrsAmf0Any::number(1024)); | ||||
|         obj->set("height", SrsAmf0Any::number(576)); | ||||
|     } | ||||
| 
 | ||||
| 8. serialize AMF0 instance to bytes: | ||||
|     // parse or set by other user
 | ||||
|     SrsAmf0Any* any = ...; | ||||
|      | ||||
|     char* bytes = new char[any->total_size()]; | ||||
|      | ||||
|     SrsStream stream; | ||||
|     stream.initialize(bytes); | ||||
|      | ||||
|     any->write(&stream); | ||||
| 
 | ||||
| @remark: for detail usage, see interfaces of each object. | ||||
| @remark: all examples ignore the error process. | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| ////////////////////////////////////////////////////////////////////////
 | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| * any amf0 value. | ||||
| * 2.1 Types Overview | ||||
| * value-type = number-type | boolean-type | string-type | object-type  | ||||
| *         | null-marker | undefined-marker | reference-type | ecma-array-type  | ||||
| *         | strict-array-type | date-type | long-string-type | xml-document-type  | ||||
| *         | typed-object-type | ||||
| */ | ||||
| class SrsAmf0Any | ||||
| { | ||||
| public: | ||||
|     char marker; | ||||
| public: | ||||
|     SrsAmf0Any(); | ||||
|     virtual ~SrsAmf0Any(); | ||||
| // type identify, user should identify the type then convert from/to value.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 string. | ||||
|     * @return true if instance is an AMF0 string; otherwise, false. | ||||
|     * @remark, if true, use to_string() to get its value. | ||||
|     */ | ||||
|     virtual bool is_string(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 boolean. | ||||
|     * @return true if instance is an AMF0 boolean; otherwise, false. | ||||
|     * @remark, if true, use to_boolean() to get its value. | ||||
|     */ | ||||
|     virtual bool is_boolean(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 number. | ||||
|     * @return true if instance is an AMF0 number; otherwise, false. | ||||
|     * @remark, if true, use to_number() to get its value. | ||||
|     */ | ||||
|     virtual bool is_number(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 null. | ||||
|     * @return true if instance is an AMF0 null; otherwise, false. | ||||
|     */ | ||||
|     virtual bool is_null(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 undefined. | ||||
|     * @return true if instance is an AMF0 undefined; otherwise, false. | ||||
|     */ | ||||
|     virtual bool is_undefined(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 object. | ||||
|     * @return true if instance is an AMF0 object; otherwise, false. | ||||
|     * @remark, if true, use to_object() to get its value. | ||||
|     */ | ||||
|     virtual bool is_object(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 object-EOF. | ||||
|     * @return true if instance is an AMF0 object-EOF; otherwise, false. | ||||
|     */ | ||||
|     virtual bool is_object_eof(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 ecma-array. | ||||
|     * @return true if instance is an AMF0 ecma-array; otherwise, false. | ||||
|     * @remark, if true, use to_ecma_array() to get its value. | ||||
|     */ | ||||
|     virtual bool is_ecma_array(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 strict-array. | ||||
|     * @return true if instance is an AMF0 strict-array; otherwise, false. | ||||
|     * @remark, if true, use to_strict_array() to get its value. | ||||
|     */ | ||||
|     virtual bool is_strict_array(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 date. | ||||
|     * @return true if instance is an AMF0 date; otherwise, false. | ||||
|     * @remark, if true, use to_date() to get its value. | ||||
|     */ | ||||
|     virtual bool is_date(); | ||||
|     /**
 | ||||
|     * whether current instance is an AMF0 object, object-EOF, ecma-array or strict-array. | ||||
|     */ | ||||
|     virtual bool is_complex_object(); | ||||
| // get value of instance
 | ||||
| public: | ||||
|     /**
 | ||||
|     * get a string copy of instance. | ||||
|     * @remark assert is_string(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual std::string to_str(); | ||||
|     /**
 | ||||
|     * get the raw str of instance, | ||||
|     * user can directly set the content of str. | ||||
|     * @remark assert is_string(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual const char* to_str_raw(); | ||||
|     /**
 | ||||
|     * convert instance to amf0 boolean, | ||||
|     * @remark assert is_boolean(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual bool to_boolean(); | ||||
|     /**
 | ||||
|     * convert instance to amf0 number, | ||||
|     * @remark assert is_number(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual double to_number(); | ||||
|     /**
 | ||||
|     * convert instance to date, | ||||
|     * @remark assert is_date(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual int64_t to_date(); | ||||
|     virtual int16_t to_date_time_zone(); | ||||
|     /**
 | ||||
|     * convert instance to amf0 object, | ||||
|     * @remark assert is_object(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual SrsAmf0Object* to_object(); | ||||
|     /**
 | ||||
|     * convert instance to ecma array, | ||||
|     * @remark assert is_ecma_array(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual SrsAmf0EcmaArray* to_ecma_array(); | ||||
|     /**
 | ||||
|     * convert instance to strict array, | ||||
|     * @remark assert is_strict_array(), user must ensure the type then convert. | ||||
|     */ | ||||
|     virtual SrsAmf0StrictArray* to_strict_array(); | ||||
| // set value of instance
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the number of any when is_number() indicates true. | ||||
|     * user must ensure the type is a number, or assert failed. | ||||
|     */ | ||||
|     virtual void set_number(double value); | ||||
| // serialize/deseriaize instance.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * get the size of amf0 any, including the marker size. | ||||
|     * the size is the bytes which instance serialized to. | ||||
|     */ | ||||
|     virtual int total_size() = 0; | ||||
|     /**
 | ||||
|     * read AMF0 instance from stream. | ||||
|     */ | ||||
|     virtual int read(SrsStream* stream) = 0; | ||||
|     /**
 | ||||
|     * write AMF0 instance to stream. | ||||
|     */ | ||||
|     virtual int write(SrsStream* stream) = 0; | ||||
|     /**
 | ||||
|     * copy current AMF0 instance. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* copy() = 0; | ||||
|     /**
 | ||||
|     * human readable print  | ||||
|     * @param pdata, output the heap data, NULL to ignore. | ||||
|     * @return return the *pdata for print. NULL to ignore. | ||||
|     * @remark user must free the data returned or output by pdata. | ||||
|     */ | ||||
|     virtual char* human_print(char** pdata, int* psize); | ||||
| // create AMF0 instance.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * create an AMF0 string instance, set string content by value. | ||||
|     */ | ||||
|     static SrsAmf0Any* str(const char* value = NULL);  | ||||
|     /**
 | ||||
|     * create an AMF0 boolean instance, set boolean content by value. | ||||
|     */ | ||||
|     static SrsAmf0Any* boolean(bool value = false); | ||||
|     /**
 | ||||
|     * create an AMF0 number instance, set number content by value. | ||||
|     */ | ||||
|     static SrsAmf0Any* number(double value = 0.0); | ||||
|     /**
 | ||||
|     * create an AMF0 date instance | ||||
|     */ | ||||
|     static SrsAmf0Any* date(int64_t value = 0); | ||||
|     /**
 | ||||
|     * create an AMF0 null instance | ||||
|     */ | ||||
|     static SrsAmf0Any* null(); | ||||
|     /**
 | ||||
|     * create an AMF0 undefined instance | ||||
|     */ | ||||
|     static SrsAmf0Any* undefined(); | ||||
|     /**
 | ||||
|     * create an AMF0 empty object instance | ||||
|     */ | ||||
|     static SrsAmf0Object* object(); | ||||
|     /**
 | ||||
|     * create an AMF0 object-EOF instance | ||||
|     */ | ||||
|     static SrsAmf0Any* object_eof(); | ||||
|     /**
 | ||||
|     * create an AMF0 empty ecma-array instance | ||||
|     */ | ||||
|     static SrsAmf0EcmaArray* ecma_array(); | ||||
|     /**
 | ||||
|     * create an AMF0 empty strict-array instance | ||||
|     */ | ||||
|     static SrsAmf0StrictArray* strict_array(); | ||||
| // discovery instance from stream
 | ||||
| public: | ||||
|     /**
 | ||||
|     * discovery AMF0 instance from stream | ||||
|     * @param ppvalue, output the discoveried AMF0 instance. | ||||
|     *       NULL if error. | ||||
|     * @remark, instance is created without read from stream, user must | ||||
|     *       use (*ppvalue)->read(stream) to get the instance. | ||||
|     */ | ||||
|     static int discovery(SrsStream* stream, SrsAmf0Any** ppvalue); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * 2.5 Object Type | ||||
| * anonymous-object-type = object-marker *(object-property) | ||||
| * object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) | ||||
| */ | ||||
| class SrsAmf0Object : public SrsAmf0Any | ||||
| { | ||||
| private: | ||||
|     _srs_internal::SrsUnSortedHashtable* properties; | ||||
|     _srs_internal::SrsAmf0ObjectEOF* eof; | ||||
| private: | ||||
|     friend class SrsAmf0Any; | ||||
|     /**
 | ||||
|     * make amf0 object to private, | ||||
|     * use should never declare it, use SrsAmf0Any::object() to create it. | ||||
|     */ | ||||
|     SrsAmf0Object(); | ||||
| public: | ||||
|     virtual ~SrsAmf0Object(); | ||||
| // serialize/deserialize to/from stream.
 | ||||
| public: | ||||
|     virtual int total_size(); | ||||
|     virtual int read(SrsStream* stream); | ||||
|     virtual int write(SrsStream* stream); | ||||
|     virtual SrsAmf0Any* copy(); | ||||
| // properties iteration
 | ||||
| public: | ||||
|     /**
 | ||||
|     * clear all propergies. | ||||
|     */ | ||||
|     virtual void clear(); | ||||
|     /**
 | ||||
|     * get the count of properties(key:value). | ||||
|     */ | ||||
|     virtual int count(); | ||||
|     /**
 | ||||
|     * get the property(key:value) key at index. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual std::string key_at(int index); | ||||
|     /**
 | ||||
|     * get the property(key:value) key raw bytes at index. | ||||
|     * user can directly set the key bytes. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual const char* key_raw_at(int index); | ||||
|     /**
 | ||||
|     * get the property(key:value) value at index. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual SrsAmf0Any* value_at(int index); | ||||
| // property set/get.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the property(key:value) of object, | ||||
|     * @param key, string property name. | ||||
|     * @param value, an AMF0 instance property value. | ||||
|     * @remark user should never free the value, this instance will manage it. | ||||
|     */ | ||||
|     virtual void set(std::string key, SrsAmf0Any* value); | ||||
|     /**
 | ||||
|     * get the property(key:value) of object, | ||||
|     * @param name, the property name/key | ||||
|     * @return the property AMF0 value, NULL if not found. | ||||
|     * @remark user should never free the returned value, copy it if needed. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* get_property(std::string name); | ||||
|     /**
 | ||||
|     * get the string property, ensure the property is_string(). | ||||
|     * @return the property AMF0 value, NULL if not found, or not a string. | ||||
|     * @remark user should never free the returned value, copy it if needed. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* ensure_property_string(std::string name); | ||||
|     /**
 | ||||
|     * get the number property, ensure the property is_number(). | ||||
|     * @return the property AMF0 value, NULL if not found, or not a number. | ||||
|     * @remark user should never free the returned value, copy it if needed. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* ensure_property_number(std::string name); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * 2.10 ECMA Array Type | ||||
| * ecma-array-type = associative-count *(object-property) | ||||
| * associative-count = U32 | ||||
| * object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker) | ||||
| */ | ||||
| class SrsAmf0EcmaArray : public SrsAmf0Any | ||||
| { | ||||
| private: | ||||
|     _srs_internal::SrsUnSortedHashtable* properties; | ||||
|     _srs_internal::SrsAmf0ObjectEOF* eof; | ||||
|     int32_t _count; | ||||
| private: | ||||
|     friend class SrsAmf0Any; | ||||
|     /**
 | ||||
|     * make amf0 object to private, | ||||
|     * use should never declare it, use SrsAmf0Any::ecma_array() to create it. | ||||
|     */ | ||||
|     SrsAmf0EcmaArray(); | ||||
| public: | ||||
|     virtual ~SrsAmf0EcmaArray(); | ||||
| // serialize/deserialize to/from stream.
 | ||||
| public: | ||||
|     virtual int total_size(); | ||||
|     virtual int read(SrsStream* stream); | ||||
|     virtual int write(SrsStream* stream); | ||||
|     virtual SrsAmf0Any* copy(); | ||||
| // properties iteration
 | ||||
| public: | ||||
|     /**
 | ||||
|     * clear all propergies. | ||||
|     */ | ||||
|     virtual void clear(); | ||||
|     /**
 | ||||
|     * get the count of properties(key:value). | ||||
|     */ | ||||
|     virtual int count(); | ||||
|     /**
 | ||||
|     * get the property(key:value) key at index. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual std::string key_at(int index); | ||||
|     /**
 | ||||
|     * get the property(key:value) key raw bytes at index. | ||||
|     * user can directly set the key bytes. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual const char* key_raw_at(int index); | ||||
|     /**
 | ||||
|     * get the property(key:value) value at index. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual SrsAmf0Any* value_at(int index); | ||||
| // property set/get.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the property(key:value) of array, | ||||
|     * @param key, string property name. | ||||
|     * @param value, an AMF0 instance property value. | ||||
|     * @remark user should never free the value, this instance will manage it. | ||||
|     */ | ||||
|     virtual void set(std::string key, SrsAmf0Any* value); | ||||
|     /**
 | ||||
|     * get the property(key:value) of array, | ||||
|     * @param name, the property name/key | ||||
|     * @return the property AMF0 value, NULL if not found. | ||||
|     * @remark user should never free the returned value, copy it if needed. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* get_property(std::string name); | ||||
|     /**
 | ||||
|     * get the string property, ensure the property is_string(). | ||||
|     * @return the property AMF0 value, NULL if not found, or not a string. | ||||
|     * @remark user should never free the returned value, copy it if needed. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* ensure_property_string(std::string name); | ||||
|     /**
 | ||||
|     * get the number property, ensure the property is_number(). | ||||
|     * @return the property AMF0 value, NULL if not found, or not a number. | ||||
|     * @remark user should never free the returned value, copy it if needed. | ||||
|     */ | ||||
|     virtual SrsAmf0Any* ensure_property_number(std::string name); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * 2.12 Strict Array Type | ||||
| * array-count = U32  | ||||
| * strict-array-type = array-count *(value-type) | ||||
| */ | ||||
| class SrsAmf0StrictArray : public SrsAmf0Any | ||||
| { | ||||
| private: | ||||
|     std::vector<SrsAmf0Any*> properties; | ||||
|     int32_t _count; | ||||
| private: | ||||
|     friend class SrsAmf0Any; | ||||
|     /**
 | ||||
|     * make amf0 object to private, | ||||
|     * use should never declare it, use SrsAmf0Any::strict_array() to create it. | ||||
|     */ | ||||
|     SrsAmf0StrictArray(); | ||||
| public: | ||||
|     virtual ~SrsAmf0StrictArray(); | ||||
| // serialize/deserialize to/from stream.
 | ||||
| public: | ||||
|     virtual int total_size(); | ||||
|     virtual int read(SrsStream* stream); | ||||
|     virtual int write(SrsStream* stream); | ||||
|     virtual SrsAmf0Any* copy(); | ||||
| // properties iteration
 | ||||
| public: | ||||
|     /**
 | ||||
|     * clear all elements. | ||||
|     */ | ||||
|     virtual void clear(); | ||||
|     /**
 | ||||
|     * get the count of elements | ||||
|     */ | ||||
|     virtual int count(); | ||||
|     /**
 | ||||
|     * get the elements key at index. | ||||
|     * @remark: max index is count(). | ||||
|     */ | ||||
|     virtual SrsAmf0Any* at(int index); | ||||
| // property set/get.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * append new element to array | ||||
|     * @param any, an AMF0 instance property value. | ||||
|     * @remark user should never free the any, this instance will manage it. | ||||
|     */ | ||||
|     virtual void append(SrsAmf0Any* any); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the class to get amf0 object size | ||||
| */ | ||||
| class SrsAmf0Size | ||||
| { | ||||
| public: | ||||
|     static int utf8(std::string value); | ||||
|     static int str(std::string value); | ||||
|     static int number(); | ||||
|     static int date(); | ||||
|     static int null(); | ||||
|     static int undefined(); | ||||
|     static int boolean(); | ||||
|     static int object(SrsAmf0Object* obj); | ||||
|     static int object_eof(); | ||||
|     static int ecma_array(SrsAmf0EcmaArray* arr); | ||||
|     static int strict_array(SrsAmf0StrictArray* arr); | ||||
|     static int any(SrsAmf0Any* o); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * read anything from stream. | ||||
| * @param ppvalue, the output amf0 any elem. | ||||
| *         NULL if error; otherwise, never NULL and user must free it. | ||||
| */ | ||||
| extern int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any** ppvalue); | ||||
| 
 | ||||
| /**
 | ||||
| * read amf0 string from stream. | ||||
| * 2.4 String Type | ||||
| * string-type = string-marker UTF-8 | ||||
| */ | ||||
| extern int srs_amf0_read_string(SrsStream* stream, std::string& value); | ||||
| extern int srs_amf0_write_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); | ||||
| extern int srs_amf0_write_boolean(SrsStream* stream, bool value); | ||||
| 
 | ||||
| /**
 | ||||
| * read amf0 number from stream. | ||||
| * 2.2 Number Type | ||||
| * number-type = number-marker DOUBLE | ||||
| */ | ||||
| extern int srs_amf0_read_number(SrsStream* stream, double& value); | ||||
| extern int srs_amf0_write_number(SrsStream* stream, double value); | ||||
| 
 | ||||
| /**
 | ||||
| * read amf0 null from stream. | ||||
| * 2.7 null Type | ||||
| * null-type = null-marker | ||||
| */ | ||||
| extern int srs_amf0_read_null(SrsStream* stream); | ||||
| extern int srs_amf0_write_null(SrsStream* stream); | ||||
| 
 | ||||
| /**
 | ||||
| * read amf0 undefined from stream. | ||||
| * 2.8 undefined Type | ||||
| * undefined-type = undefined-marker | ||||
| */ | ||||
| extern int srs_amf0_read_undefined(SrsStream* stream); | ||||
| extern int srs_amf0_write_undefined(SrsStream* stream); | ||||
| 
 | ||||
| // internal objects, user should never use it.
 | ||||
| namespace _srs_internal | ||||
| { | ||||
|     /**
 | ||||
|     * read amf0 string from stream. | ||||
|     * 2.4 String Type | ||||
|     * string-type = string-marker UTF-8 | ||||
|     * @return default value is empty string. | ||||
|     * @remark: use SrsAmf0Any::str() to create it. | ||||
|     */ | ||||
|     class SrsAmf0String : public SrsAmf0Any | ||||
|     { | ||||
|     public: | ||||
|         std::string value; | ||||
|     private: | ||||
|         friend class SrsAmf0Any; | ||||
|         /**
 | ||||
|         * make amf0 string to private, | ||||
|         * use should never declare it, use SrsAmf0Any::str() to create it. | ||||
|         */ | ||||
|         SrsAmf0String(const char* _value); | ||||
|     public: | ||||
|         virtual ~SrsAmf0String(); | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * 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. | ||||
|     */ | ||||
|     class SrsAmf0Boolean : public SrsAmf0Any | ||||
|     { | ||||
|     public: | ||||
|         bool value; | ||||
|     private: | ||||
|         friend class SrsAmf0Any; | ||||
|         /**
 | ||||
|         * make amf0 boolean to private, | ||||
|         * use should never declare it, use SrsAmf0Any::boolean() to create it. | ||||
|         */ | ||||
|         SrsAmf0Boolean(bool _value); | ||||
|     public: | ||||
|         virtual ~SrsAmf0Boolean(); | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * read amf0 number from stream. | ||||
|     * 2.2 Number Type | ||||
|     * number-type = number-marker DOUBLE | ||||
|     * @return default value is 0. | ||||
|     */ | ||||
|     class SrsAmf0Number : public SrsAmf0Any | ||||
|     { | ||||
|     public: | ||||
|         double value; | ||||
|     private: | ||||
|         friend class SrsAmf0Any; | ||||
|         /**
 | ||||
|         * make amf0 number to private, | ||||
|         * use should never declare it, use SrsAmf0Any::number() to create it. | ||||
|         */ | ||||
|         SrsAmf0Number(double _value); | ||||
|     public: | ||||
|         virtual ~SrsAmf0Number(); | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * 2.13 Date Type | ||||
|     * time-zone = S16 ; reserved, not supported should be set to 0x0000 | ||||
|     * date-type = date-marker DOUBLE time-zone | ||||
|     * @see: https://github.com/winlinvip/simple-rtmp-server/issues/185
 | ||||
|     */ | ||||
|     class SrsAmf0Date : public SrsAmf0Any | ||||
|     { | ||||
|     private: | ||||
|         int64_t _date_value; | ||||
|         int16_t _time_zone; | ||||
|     private: | ||||
|         friend class SrsAmf0Any; | ||||
|         /**
 | ||||
|         * make amf0 date to private, | ||||
|         * use should never declare it, use SrsAmf0Any::date() to create it. | ||||
|         */ | ||||
|         SrsAmf0Date(int64_t value); | ||||
|     public: | ||||
|         virtual ~SrsAmf0Date(); | ||||
|     // serialize/deserialize to/from stream.
 | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     public: | ||||
|         /**
 | ||||
|         * get the date value. | ||||
|         */ | ||||
|         virtual int64_t date(); | ||||
|         /**
 | ||||
|         * get the time_zone. | ||||
|         */ | ||||
|         virtual int16_t time_zone(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * read amf0 null from stream. | ||||
|     * 2.7 null Type | ||||
|     * null-type = null-marker | ||||
|     */ | ||||
|     class SrsAmf0Null : public SrsAmf0Any | ||||
|     { | ||||
|     private: | ||||
|         friend class SrsAmf0Any; | ||||
|         /**
 | ||||
|         * make amf0 null to private, | ||||
|         * use should never declare it, use SrsAmf0Any::null() to create it. | ||||
|         */ | ||||
|         SrsAmf0Null(); | ||||
|     public: | ||||
|         virtual ~SrsAmf0Null(); | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * read amf0 undefined from stream. | ||||
|     * 2.8 undefined Type | ||||
|     * undefined-type = undefined-marker | ||||
|     */ | ||||
|     class SrsAmf0Undefined : public SrsAmf0Any | ||||
|     { | ||||
|     private: | ||||
|         friend class SrsAmf0Any; | ||||
|         /**
 | ||||
|         * make amf0 undefined to private, | ||||
|         * use should never declare it, use SrsAmf0Any::undefined() to create it. | ||||
|         */ | ||||
|         SrsAmf0Undefined(); | ||||
|     public: | ||||
|         virtual ~SrsAmf0Undefined(); | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * to ensure in inserted order. | ||||
|     * for the FMLE will crash when AMF0Object is not ordered by inserted, | ||||
|     * if ordered in map, the string compare order, the FMLE will creash when | ||||
|     * get the response of connect app. | ||||
|     */ | ||||
|     class SrsUnSortedHashtable | ||||
|     { | ||||
|     private: | ||||
|         typedef std::pair<std::string, SrsAmf0Any*> SrsAmf0ObjectPropertyType; | ||||
|         std::vector<SrsAmf0ObjectPropertyType> properties; | ||||
|     public: | ||||
|         SrsUnSortedHashtable(); | ||||
|         virtual ~SrsUnSortedHashtable(); | ||||
|     public: | ||||
|         virtual int count(); | ||||
|         virtual void clear(); | ||||
|         virtual std::string key_at(int index); | ||||
|         virtual const char* key_raw_at(int index); | ||||
|         virtual SrsAmf0Any* value_at(int index); | ||||
|         virtual void set(std::string key, SrsAmf0Any* value); | ||||
|     public: | ||||
|         virtual SrsAmf0Any* get_property(std::string name); | ||||
|         virtual SrsAmf0Any* ensure_property_string(std::string name); | ||||
|         virtual SrsAmf0Any* ensure_property_number(std::string name); | ||||
|     public: | ||||
|         virtual void copy(SrsUnSortedHashtable* src); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * 2.11 Object End Type | ||||
|     * object-end-type = UTF-8-empty object-end-marker | ||||
|     * 0x00 0x00 0x09 | ||||
|     */ | ||||
|     class SrsAmf0ObjectEOF : public SrsAmf0Any | ||||
|     { | ||||
|     public: | ||||
|         SrsAmf0ObjectEOF(); | ||||
|         virtual ~SrsAmf0ObjectEOF(); | ||||
|     public: | ||||
|         virtual int total_size(); | ||||
|         virtual int read(SrsStream* stream); | ||||
|         virtual int write(SrsStream* stream); | ||||
|         virtual SrsAmf0Any* copy(); | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|     * read amf0 utf8 string from stream. | ||||
|     * 1.3.1 Strings and UTF-8 | ||||
|     * UTF-8 = U16 *(UTF8-char) | ||||
|     * UTF8-char = UTF8-1 | UTF8-2 | UTF8-3 | UTF8-4 | ||||
|     * UTF8-1 = %x00-7F | ||||
|     * @remark only support UTF8-1 char. | ||||
|     */ | ||||
|     extern int srs_amf0_read_utf8(SrsStream* stream, std::string& value); | ||||
|     extern int srs_amf0_write_utf8(SrsStream* stream, std::string value); | ||||
|      | ||||
|     extern bool srs_amf0_is_object_eof(SrsStream* stream); | ||||
|     extern int srs_amf0_write_object_eof(SrsStream* stream, SrsAmf0ObjectEOF* value); | ||||
|      | ||||
|     extern int srs_amf0_write_any(SrsStream* stream, SrsAmf0Any* value); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										194
									
								
								trunk/src/protocol/srs_rtmp_buffer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								trunk/src/protocol/srs_rtmp_buffer.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,194 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include <srs_rtmp_buffer.hpp> | ||||
| 
 | ||||
| #include <srs_kernel_error.hpp> | ||||
| #include <srs_kernel_log.hpp> | ||||
| #include <srs_kernel_utility.hpp> | ||||
| #include <srs_core_performance.hpp> | ||||
| 
 | ||||
| // the default recv buffer size, 128KB.
 | ||||
| #define SRS_DEFAULT_RECV_BUFFER_SIZE 131072 | ||||
| 
 | ||||
| // limit user-space buffer to 256KB, for 3Mbps stream delivery.
 | ||||
| //      800*2000/8=200000B(about 195KB).
 | ||||
| // @remark it's ok for higher stream, the buffer is ok for one chunk is 256KB.
 | ||||
| #define SRS_MAX_SOCKET_BUFFER 262144 | ||||
| 
 | ||||
| // the max header size,
 | ||||
| // @see SrsProtocol::read_message_header().
 | ||||
| #define SRS_RTMP_MAX_MESSAGE_HEADER 11 | ||||
| 
 | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
| IMergeReadHandler::IMergeReadHandler() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| IMergeReadHandler::~IMergeReadHandler() | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| SrsFastBuffer::SrsFastBuffer() | ||||
| { | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
|     merged_read = false; | ||||
|     _handler = NULL; | ||||
| #endif | ||||
|      | ||||
|     nb_buffer = SRS_DEFAULT_RECV_BUFFER_SIZE; | ||||
|     buffer = new char[nb_buffer]; | ||||
|     p = end = buffer; | ||||
| } | ||||
| 
 | ||||
| void SrsFastBuffer::set_buffer(int buffer_size) | ||||
| { | ||||
|     // the user-space buffer size limit to a max value.
 | ||||
|     int nb_max_buf = srs_min(buffer_size, SRS_MAX_SOCKET_BUFFER); | ||||
|     if (nb_max_buf < buffer_size) { | ||||
|         srs_warn("limit the user-space buffer from %d to %d", buffer_size, nb_max_buf); | ||||
|     } | ||||
| 
 | ||||
|     // only realloc when buffer changed bigger
 | ||||
|     if (nb_max_buf <= nb_buffer) { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     int start = p - buffer; | ||||
|     int cap = end - p; | ||||
|      | ||||
|     char* buf = new char[nb_max_buf]; | ||||
|     if (cap > 0) { | ||||
|         memcpy(buf, buffer, nb_buffer); | ||||
|     } | ||||
|     srs_freep(buffer); | ||||
|      | ||||
|     buffer = buf; | ||||
|     p = buffer + start; | ||||
|     end = p + cap; | ||||
| } | ||||
| 
 | ||||
| SrsFastBuffer::~SrsFastBuffer() | ||||
| { | ||||
|     srs_freep(buffer); | ||||
| } | ||||
| 
 | ||||
| char SrsFastBuffer::read_1byte() | ||||
| { | ||||
|     srs_assert(end - p >= 1); | ||||
|     return *p++; | ||||
| } | ||||
| 
 | ||||
| char* SrsFastBuffer::read_slice(int size) | ||||
| { | ||||
|     srs_assert(end - p >= size); | ||||
|     srs_assert(p + size > buffer); | ||||
|      | ||||
|     char* ptr = p; | ||||
|     p += size; | ||||
|      | ||||
|     // reset when consumed all.
 | ||||
|     if (p == end) { | ||||
|         p = end = buffer; | ||||
|         srs_verbose("all consumed, reset fast buffer"); | ||||
|     } | ||||
| 
 | ||||
|     return ptr; | ||||
| } | ||||
| 
 | ||||
| void SrsFastBuffer::skip(int size) | ||||
| { | ||||
|     srs_assert(end - p >= size); | ||||
|     srs_assert(p + size > buffer); | ||||
|     p += size; | ||||
| } | ||||
| 
 | ||||
| int SrsFastBuffer::grow(ISrsBufferReader* reader, int required_size) | ||||
| { | ||||
|     int ret = ERROR_SUCCESS; | ||||
| 
 | ||||
|     // generally the required size is ok.
 | ||||
|     if (end - p >= required_size) { | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     // must be positive.
 | ||||
|     srs_assert(required_size > 0); | ||||
| 
 | ||||
|     // when read payload or there is no space to read,
 | ||||
|     // reset the buffer with exists bytes.
 | ||||
|     int max_to_read = buffer + nb_buffer - end; | ||||
|     if (required_size > SRS_RTMP_MAX_MESSAGE_HEADER || max_to_read < required_size) { | ||||
|         int nb_cap = end - p; | ||||
|         srs_verbose("move fast buffer %d bytes", nb_cap); | ||||
|         if (nb_cap < nb_buffer) { | ||||
|             buffer = (char*)memmove(buffer, p, nb_cap); | ||||
|             p = buffer; | ||||
|             end = p + nb_cap; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // directly check the available bytes to read in buffer.
 | ||||
|     max_to_read = buffer + nb_buffer - end; | ||||
|     if (max_to_read < required_size) { | ||||
|         ret = ERROR_READER_BUFFER_OVERFLOW; | ||||
|         srs_error("buffer overflow, required=%d, max=%d, ret=%d", required_size, nb_buffer, ret); | ||||
|         return ret; | ||||
|     } | ||||
| 
 | ||||
|     // buffer is ok, read required size of bytes.
 | ||||
|     while (end - p < required_size) { | ||||
|         ssize_t nread; | ||||
|         if ((ret = reader->read(end, max_to_read, &nread)) != ERROR_SUCCESS) { | ||||
|             return ret; | ||||
|         } | ||||
|          | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
|         /**
 | ||||
|         * to improve read performance, merge some packets then read, | ||||
|         * when it on and read small bytes, we sleep to wait more data., | ||||
|         * that is, we merge some data to read together. | ||||
|         * @see https://github.com/winlinvip/simple-rtmp-server/issues/241
 | ||||
|         */ | ||||
|         if (merged_read && _handler) { | ||||
|             _handler->on_read(nread); | ||||
|         } | ||||
| #endif | ||||
|          | ||||
|         // we just move the ptr to next.
 | ||||
|         srs_assert((int)nread > 0); | ||||
|         end += nread; | ||||
|     } | ||||
|      | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
| void SrsFastBuffer::set_merge_read(bool v, IMergeReadHandler* handler) | ||||
| { | ||||
|     merged_read = v; | ||||
|     _handler = handler; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										138
									
								
								trunk/src/protocol/srs_rtmp_buffer.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								trunk/src/protocol/srs_rtmp_buffer.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_PROTOCOL_BUFFER_HPP | ||||
| #define SRS_PROTOCOL_BUFFER_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_buffer.hpp> | ||||
| */ | ||||
| 
 | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| #include <srs_rtmp_io.hpp> | ||||
| #include <srs_core_performance.hpp> | ||||
| #include <srs_kernel_buffer.hpp> | ||||
| 
 | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
| /**
 | ||||
| * to improve read performance, merge some packets then read, | ||||
| * when it on and read small bytes, we sleep to wait more data., | ||||
| * that is, we merge some data to read together. | ||||
| * @see https://github.com/winlinvip/simple-rtmp-server/issues/241
 | ||||
| */ | ||||
| class IMergeReadHandler | ||||
| { | ||||
| public: | ||||
|     IMergeReadHandler(); | ||||
|     virtual ~IMergeReadHandler(); | ||||
| public: | ||||
|     /**
 | ||||
|     * when read from channel, notice the merge handler to sleep for | ||||
|     * some small bytes. | ||||
|     * @remark, it only for server-side, client srs-librtmp just ignore. | ||||
|     */ | ||||
|     virtual void on_read(ssize_t nread) = 0; | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
| * the buffer provices bytes cache for protocol. generally,  | ||||
| * protocol recv data from socket, put into buffer, decode to RTMP message. | ||||
| */ | ||||
| // TODO: FIXME: add utest for it.
 | ||||
| class SrsFastBuffer | ||||
| { | ||||
| private: | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
|     // the merged handler
 | ||||
|     bool merged_read; | ||||
|     IMergeReadHandler* _handler; | ||||
| #endif | ||||
|     // the user-space buffer to fill by reader,
 | ||||
|     // which use fast index and reset when chunk body read ok.
 | ||||
|     // @see https://github.com/winlinvip/simple-rtmp-server/issues/248
 | ||||
|     // ptr to the current read position.
 | ||||
|     char* p; | ||||
|     // ptr to the content end.
 | ||||
|     char* end; | ||||
|     // ptr to the buffer.
 | ||||
|     //      buffer <= p <= end <= buffer+nb_buffer
 | ||||
|     char* buffer; | ||||
|     // the max size of buffer.
 | ||||
|     int nb_buffer; | ||||
| public: | ||||
|     SrsFastBuffer(); | ||||
|     virtual ~SrsFastBuffer(); | ||||
| public: | ||||
|     /**
 | ||||
|     * create buffer with specifeid size. | ||||
|     * @param buffer the size of buffer. | ||||
|     * @remark when MR(SRS_PERF_MERGED_READ) disabled, always set to 8K. | ||||
|     * @remark when buffer changed, the previous ptr maybe invalid. | ||||
|     * @see https://github.com/winlinvip/simple-rtmp-server/issues/241
 | ||||
|     */ | ||||
|     virtual void set_buffer(int buffer_size); | ||||
| public: | ||||
|     /**
 | ||||
|     * read 1byte from buffer, move to next bytes. | ||||
|     * @remark assert buffer already grow(1). | ||||
|     */ | ||||
|     virtual char read_1byte(); | ||||
|     /**
 | ||||
|     * read a slice in size bytes, move to next bytes. | ||||
|     * user can use this char* ptr directly, and should never free it. | ||||
|     * @remark assert buffer already grow(size). | ||||
|     * @remark the ptr returned maybe invalid after grow(x). | ||||
|     */ | ||||
|     virtual char* read_slice(int size); | ||||
|     /**
 | ||||
|     * skip some bytes in buffer. | ||||
|     * @param size the bytes to skip. positive to next; negative to previous. | ||||
|     * @remark assert buffer already grow(size). | ||||
|     */ | ||||
|     virtual void skip(int size); | ||||
| public: | ||||
|     /**
 | ||||
|     * grow buffer to the required size, loop to read from skt to fill. | ||||
|     * @param reader, read more bytes from reader to fill the buffer to required size. | ||||
|     * @param required_size, loop to fill to ensure buffer size to required.  | ||||
|     * @return an int error code, error if required_size negative. | ||||
|     * @remark, we actually maybe read more than required_size, maybe 4k for example. | ||||
|     */ | ||||
|     virtual int grow(ISrsBufferReader* reader, int required_size); | ||||
| public: | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
|     /**
 | ||||
|     * to improve read performance, merge some packets then read, | ||||
|     * when it on and read small bytes, we sleep to wait more data., | ||||
|     * that is, we merge some data to read together. | ||||
|     * @param v true to ename merged read. | ||||
|     * @param handler the handler when merge read is enabled. | ||||
|     * @see https://github.com/winlinvip/simple-rtmp-server/issues/241
 | ||||
|     */ | ||||
|     virtual void set_merge_read(bool v, IMergeReadHandler* handler); | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										1383
									
								
								trunk/src/protocol/srs_rtmp_handshake.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1383
									
								
								trunk/src/protocol/srs_rtmp_handshake.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										546
									
								
								trunk/src/protocol/srs_rtmp_handshake.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										546
									
								
								trunk/src/protocol/srs_rtmp_handshake.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,546 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_RTMP_PROTOCOL_HANDSHKAE_HPP | ||||
| #define SRS_RTMP_PROTOCOL_HANDSHKAE_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_handshake.hpp> | ||||
| */ | ||||
| 
 | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| class ISrsProtocolReaderWriter; | ||||
| class SrsComplexHandshake; | ||||
| class SrsHandshakeBytes; | ||||
| class SrsStream; | ||||
| 
 | ||||
| #ifdef SRS_AUTO_SSL | ||||
| 
 | ||||
| // for openssl.
 | ||||
| #include <openssl/hmac.h> | ||||
| 
 | ||||
| namespace _srs_internal | ||||
| { | ||||
|     // the digest key generate size.
 | ||||
|     #define __SRS_OpensslHashSize 512 | ||||
|     extern u_int8_t SrsGenuineFMSKey[]; | ||||
|     extern u_int8_t SrsGenuineFPKey[]; | ||||
|     int openssl_HMACsha256(const void* key, int key_size, const void* data, int data_size, void* digest); | ||||
|     int openssl_generate_key(char* public_key, int32_t size); | ||||
|      | ||||
|     /**
 | ||||
|     * the DH wrapper. | ||||
|     */ | ||||
|     class SrsDH | ||||
|     { | ||||
|     private: | ||||
|         DH* pdh; | ||||
|     public: | ||||
|         SrsDH(); | ||||
|         virtual ~SrsDH(); | ||||
|     public: | ||||
|         /**
 | ||||
|         * initialize dh, generate the public and private key. | ||||
|         * @param ensure_128bytes_public_key whether ensure public key is 128bytes, | ||||
|         *       sometimes openssl generate 127bytes public key. | ||||
|         *       default to false to donot ensure. | ||||
|         */ | ||||
|         virtual int initialize(bool ensure_128bytes_public_key = false); | ||||
|         /**
 | ||||
|         * copy the public key. | ||||
|         * @param pkey the bytes to copy the public key. | ||||
|         * @param pkey_size the max public key size, output the actual public key size. | ||||
|         *       user should never ignore this size. | ||||
|         * @remark, when ensure_128bytes_public_key, the size always 128. | ||||
|         */ | ||||
|         virtual int copy_public_key(char* pkey, int32_t& pkey_size); | ||||
|         /**
 | ||||
|         * generate and copy the shared key. | ||||
|         * generate the shared key with peer public key. | ||||
|         * @param ppkey peer public key. | ||||
|         * @param ppkey_size the size of ppkey. | ||||
|         * @param skey the computed shared key. | ||||
|         * @param skey_size the max shared key size, output the actual shared key size. | ||||
|         *       user should never ignore this size. | ||||
|         */ | ||||
|         virtual int copy_shared_key(const char* ppkey, int32_t ppkey_size, char* skey, int32_t& skey_size); | ||||
|     private: | ||||
|         virtual int do_initialize(); | ||||
|     }; | ||||
|     /**
 | ||||
|     * the schema type. | ||||
|     */ | ||||
|     enum srs_schema_type  | ||||
|     { | ||||
|         srs_schema_invalid = 2, | ||||
|          | ||||
|         /**
 | ||||
|         * key-digest sequence | ||||
|         */ | ||||
|         srs_schema0 = 0, | ||||
|          | ||||
|         /**
 | ||||
|         * digest-key sequence | ||||
|         * @remark, FMS requires the schema1(digest-key), or connect failed. | ||||
|         */ | ||||
|         // 
 | ||||
|         srs_schema1 = 1, | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * 764bytes key structure | ||||
|     *     random-data: (offset)bytes | ||||
|     *     key-data: 128bytes | ||||
|     *     random-data: (764-offset-128-4)bytes | ||||
|     *     offset: 4bytes | ||||
|     * @see also: http://blog.csdn.net/win_lin/article/details/13006803
 | ||||
|     */ | ||||
|     class key_block | ||||
|     { | ||||
|     public: | ||||
|         // (offset)bytes
 | ||||
|         char* random0; | ||||
|         int random0_size; | ||||
|          | ||||
|         // 128bytes
 | ||||
|         char key[128]; | ||||
|          | ||||
|         // (764-offset-128-4)bytes
 | ||||
|         char* random1; | ||||
|         int random1_size; | ||||
|          | ||||
|         // 4bytes
 | ||||
|         int32_t offset; | ||||
|     public: | ||||
|         key_block(); | ||||
|         virtual ~key_block(); | ||||
|     public: | ||||
|         // parse key block from c1s1.
 | ||||
|         // if created, user must free it by srs_key_block_free
 | ||||
|         // @stream contains c1s1_key_bytes the key start bytes
 | ||||
|         int parse(SrsStream* stream); | ||||
|     private: | ||||
|         // calc the offset of key,
 | ||||
|         // the key->offset cannot be used as the offset of key.
 | ||||
|         int calc_valid_offset(); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * 764bytes digest structure | ||||
|     *     offset: 4bytes | ||||
|     *     random-data: (offset)bytes | ||||
|     *     digest-data: 32bytes | ||||
|     *     random-data: (764-4-offset-32)bytes | ||||
|     * @see also: http://blog.csdn.net/win_lin/article/details/13006803
 | ||||
|     */ | ||||
|     class digest_block | ||||
|     { | ||||
|     public: | ||||
|         // 4bytes
 | ||||
|         int32_t offset; | ||||
|          | ||||
|         // (offset)bytes
 | ||||
|         char* random0; | ||||
|         int random0_size; | ||||
|          | ||||
|         // 32bytes
 | ||||
|         char digest[32]; | ||||
|          | ||||
|         // (764-4-offset-32)bytes
 | ||||
|         char* random1; | ||||
|         int random1_size; | ||||
|     public: | ||||
|         digest_block(); | ||||
|         virtual ~digest_block(); | ||||
|     public: | ||||
|         // parse digest block from c1s1.
 | ||||
|         // if created, user must free it by srs_digest_block_free
 | ||||
|         // @stream contains c1s1_digest_bytes the digest start bytes
 | ||||
|         int parse(SrsStream* stream); | ||||
|     private: | ||||
|         // calc the offset of digest,
 | ||||
|         // the key->offset cannot be used as the offset of digest.
 | ||||
|         int calc_valid_offset(); | ||||
|     }; | ||||
|      | ||||
|     class c1s1; | ||||
|      | ||||
|     /**
 | ||||
|     * the c1s1 strategy, use schema0 or schema1. | ||||
|     * the template method class to defines common behaviors, | ||||
|     * while the concrete class to implements in schema0 or schema1. | ||||
|     */ | ||||
|     class c1s1_strategy | ||||
|     { | ||||
|     protected: | ||||
|         key_block key; | ||||
|         digest_block digest; | ||||
|     public: | ||||
|         c1s1_strategy(); | ||||
|         virtual ~c1s1_strategy(); | ||||
|     public: | ||||
|         /**
 | ||||
|         * get the scema. | ||||
|         */ | ||||
|         virtual srs_schema_type schema() = 0; | ||||
|         /**
 | ||||
|         * get the digest. | ||||
|         */ | ||||
|         virtual char* get_digest(); | ||||
|         /**
 | ||||
|         * get the key. | ||||
|         */ | ||||
|         virtual char* get_key(); | ||||
|         /**
 | ||||
|         * copy to bytes. | ||||
|         * @param size must be 1536. | ||||
|         */ | ||||
|         virtual int dump(c1s1* owner, char* _c1s1, int size); | ||||
|         /**
 | ||||
|         * server: parse the c1s1, discovery the key and digest by schema. | ||||
|         * use the c1_validate_digest() to valid the digest of c1. | ||||
|         */ | ||||
|         virtual int parse(char* _c1s1, int size) = 0; | ||||
|     public: | ||||
|         /**
 | ||||
|         * client: create and sign c1 by schema. | ||||
|         * sign the c1, generate the digest. | ||||
|         *         calc_c1_digest(c1, schema) { | ||||
|         *            get c1s1-joined from c1 by specified schema | ||||
|         *            digest-data = HMACsha256(c1s1-joined, FPKey, 30) | ||||
|         *            return digest-data; | ||||
|         *        } | ||||
|         *        random fill 1536bytes c1 // also fill the c1-128bytes-key
 | ||||
|         *        time = time() // c1[0-3]
 | ||||
|         *        version = [0x80, 0x00, 0x07, 0x02] // c1[4-7]
 | ||||
|         *        schema = choose schema0 or schema1 | ||||
|         *        digest-data = calc_c1_digest(c1, schema) | ||||
|         *        copy digest-data to c1 | ||||
|         */ | ||||
|         virtual int c1_create(c1s1* owner); | ||||
|         /**
 | ||||
|         * server: validate the parsed c1 schema | ||||
|         */ | ||||
|         virtual int c1_validate_digest(c1s1* owner, bool& is_valid); | ||||
|         /**
 | ||||
|         * server: create and sign the s1 from c1. | ||||
|         *       // decode c1 try schema0 then schema1
 | ||||
|         *       c1-digest-data = get-c1-digest-data(schema0) | ||||
|         *       if c1-digest-data equals to calc_c1_digest(c1, schema0) {   | ||||
|         *           c1-key-data = get-c1-key-data(schema0)   | ||||
|         *           schema = schema0 | ||||
|         *       } else {   | ||||
|         *           c1-digest-data = get-c1-digest-data(schema1)   | ||||
|         *           if c1-digest-data not equals to calc_c1_digest(c1, schema1) { | ||||
|         *               switch to simple handshake.   | ||||
|         *               return   | ||||
|         *           } | ||||
|         *           c1-key-data = get-c1-key-data(schema1)   | ||||
|         *           schema = schema1 | ||||
|         *       } | ||||
|         *  | ||||
|         *       // generate s1
 | ||||
|         *       random fill 1536bytes s1 | ||||
|         *       time = time() // c1[0-3]
 | ||||
|         *       version = [0x04, 0x05, 0x00, 0x01] // s1[4-7]
 | ||||
|         *       s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data) | ||||
|         *       get c1s1-joined by specified schema | ||||
|         *       s1-digest-data = HMACsha256(c1s1-joined, FMSKey, 36) | ||||
|         *       copy s1-digest-data and s1-key-data to s1. | ||||
|         * @param c1, to get the peer_pub_key of client. | ||||
|         */ | ||||
|         virtual int s1_create(c1s1* owner, c1s1* c1); | ||||
|         /**
 | ||||
|         * server: validate the parsed s1 schema | ||||
|         */ | ||||
|         virtual int s1_validate_digest(c1s1* owner, bool& is_valid); | ||||
|     public: | ||||
|         /**
 | ||||
|         * calc the digest for c1 | ||||
|         */ | ||||
|         virtual int calc_c1_digest(c1s1* owner, char*& c1_digest); | ||||
|         /**
 | ||||
|         * calc the digest for s1 | ||||
|         */ | ||||
|         virtual int calc_s1_digest(c1s1* owner, char*& s1_digest); | ||||
|         /**
 | ||||
|         * copy whole c1s1 to bytes. | ||||
|         * @param size must always be 1536 with digest, and 1504 without digest. | ||||
|         */ | ||||
|         virtual int copy_to(c1s1* owner, char* bytes, int size, bool with_digest) = 0; | ||||
|         /**
 | ||||
|         * copy time and version to stream. | ||||
|         */ | ||||
|         virtual void copy_time_version(SrsStream* stream, c1s1* owner); | ||||
|         /**
 | ||||
|         * copy key to stream. | ||||
|         */ | ||||
|         virtual void copy_key(SrsStream* stream); | ||||
|         /**
 | ||||
|         * copy digest to stream. | ||||
|         */ | ||||
|         virtual void copy_digest(SrsStream* stream, bool with_digest); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * c1s1 schema0 | ||||
|     *     key: 764bytes | ||||
|     *     digest: 764bytes | ||||
|     */ | ||||
|     class c1s1_strategy_schema0 : public c1s1_strategy | ||||
|     { | ||||
|     public: | ||||
|         c1s1_strategy_schema0(); | ||||
|         virtual ~c1s1_strategy_schema0(); | ||||
|     public: | ||||
|         virtual srs_schema_type schema(); | ||||
|         virtual int parse(char* _c1s1, int size); | ||||
|     public: | ||||
|         virtual int copy_to(c1s1* owner, char* bytes, int size, bool with_digest); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * c1s1 schema1 | ||||
|     *     digest: 764bytes | ||||
|     *     key: 764bytes | ||||
|     */ | ||||
|     class c1s1_strategy_schema1 : public c1s1_strategy | ||||
|     { | ||||
|     public: | ||||
|         c1s1_strategy_schema1(); | ||||
|         virtual ~c1s1_strategy_schema1(); | ||||
|     public: | ||||
|         virtual srs_schema_type schema(); | ||||
|         virtual int parse(char* _c1s1, int size); | ||||
|     public: | ||||
|         virtual int copy_to(c1s1* owner, char* bytes, int size, bool with_digest); | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|     * c1s1 schema0 | ||||
|     *     time: 4bytes | ||||
|     *     version: 4bytes | ||||
|     *     key: 764bytes | ||||
|     *     digest: 764bytes | ||||
|     * c1s1 schema1 | ||||
|     *     time: 4bytes | ||||
|     *     version: 4bytes | ||||
|     *     digest: 764bytes | ||||
|     *     key: 764bytes | ||||
|     * @see also: http://blog.csdn.net/win_lin/article/details/13006803
 | ||||
|     */ | ||||
|     class c1s1 | ||||
|     { | ||||
|     public: | ||||
|         // 4bytes
 | ||||
|         int32_t time; | ||||
|         // 4bytes
 | ||||
|         int32_t version; | ||||
|         // 764bytes+764bytes
 | ||||
|         c1s1_strategy* payload; | ||||
|     public: | ||||
|         c1s1(); | ||||
|         virtual ~c1s1(); | ||||
|     public: | ||||
|         /**
 | ||||
|         * get the scema. | ||||
|         */ | ||||
|         virtual srs_schema_type schema(); | ||||
|         /**
 | ||||
|         * get the digest key. | ||||
|         */ | ||||
|         virtual char* get_digest(); | ||||
|         /**
 | ||||
|         * get the key. | ||||
|         */ | ||||
|         virtual char* get_key(); | ||||
|     public: | ||||
|         /**
 | ||||
|         * copy to bytes. | ||||
|         * @param size, must always be 1536. | ||||
|         */ | ||||
|         virtual int dump(char* _c1s1, int size); | ||||
|         /**
 | ||||
|         * server: parse the c1s1, discovery the key and digest by schema. | ||||
|         * @param size, must always be 1536. | ||||
|         * use the c1_validate_digest() to valid the digest of c1. | ||||
|         * use the s1_validate_digest() to valid the digest of s1. | ||||
|         */ | ||||
|         virtual int parse(char* _c1s1, int size, srs_schema_type _schema); | ||||
|     public: | ||||
|         /**
 | ||||
|         * client: create and sign c1 by schema. | ||||
|         * sign the c1, generate the digest. | ||||
|         *         calc_c1_digest(c1, schema) { | ||||
|         *            get c1s1-joined from c1 by specified schema | ||||
|         *            digest-data = HMACsha256(c1s1-joined, FPKey, 30) | ||||
|         *            return digest-data; | ||||
|         *        } | ||||
|         *        random fill 1536bytes c1 // also fill the c1-128bytes-key
 | ||||
|         *        time = time() // c1[0-3]
 | ||||
|         *        version = [0x80, 0x00, 0x07, 0x02] // c1[4-7]
 | ||||
|         *        schema = choose schema0 or schema1 | ||||
|         *        digest-data = calc_c1_digest(c1, schema) | ||||
|         *        copy digest-data to c1 | ||||
|         */ | ||||
|         virtual int c1_create(srs_schema_type _schema); | ||||
|         /**
 | ||||
|         * server: validate the parsed c1 schema | ||||
|         */ | ||||
|         virtual int c1_validate_digest(bool& is_valid); | ||||
|     public: | ||||
|         /**
 | ||||
|         * server: create and sign the s1 from c1. | ||||
|         *       // decode c1 try schema0 then schema1
 | ||||
|         *       c1-digest-data = get-c1-digest-data(schema0) | ||||
|         *       if c1-digest-data equals to calc_c1_digest(c1, schema0) {   | ||||
|         *           c1-key-data = get-c1-key-data(schema0)   | ||||
|         *           schema = schema0 | ||||
|         *       } else {   | ||||
|         *           c1-digest-data = get-c1-digest-data(schema1)   | ||||
|         *           if c1-digest-data not equals to calc_c1_digest(c1, schema1) { | ||||
|         *               switch to simple handshake.   | ||||
|         *               return   | ||||
|         *           } | ||||
|         *           c1-key-data = get-c1-key-data(schema1)   | ||||
|         *           schema = schema1 | ||||
|         *       } | ||||
|         *  | ||||
|         *       // generate s1
 | ||||
|         *       random fill 1536bytes s1 | ||||
|         *       time = time() // c1[0-3]
 | ||||
|         *       version = [0x04, 0x05, 0x00, 0x01] // s1[4-7]
 | ||||
|         *       s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data) | ||||
|         *       get c1s1-joined by specified schema | ||||
|         *       s1-digest-data = HMACsha256(c1s1-joined, FMSKey, 36) | ||||
|         *       copy s1-digest-data and s1-key-data to s1. | ||||
|         */ | ||||
|         virtual int s1_create(c1s1* c1); | ||||
|         /**
 | ||||
|         * server: validate the parsed s1 schema | ||||
|         */ | ||||
|         virtual int s1_validate_digest(bool& is_valid); | ||||
|     }; | ||||
|      | ||||
|     /**
 | ||||
|     * the c2s2 complex handshake structure. | ||||
|     * random-data: 1504bytes | ||||
|     * digest-data: 32bytes | ||||
|     * @see also: http://blog.csdn.net/win_lin/article/details/13006803
 | ||||
|     */ | ||||
|     class c2s2 | ||||
|     { | ||||
|     public: | ||||
|         char random[1504]; | ||||
|         char digest[32]; | ||||
|     public: | ||||
|         c2s2(); | ||||
|         virtual ~c2s2(); | ||||
|     public: | ||||
|         /**
 | ||||
|         * copy to bytes. | ||||
|         * @param size, must always be 1536. | ||||
|         */ | ||||
|         virtual int dump(char* _c2s2, int size); | ||||
|         /**
 | ||||
|         * parse the c2s2 | ||||
|         * @param size, must always be 1536. | ||||
|         */ | ||||
|         virtual int parse(char* _c2s2, int size); | ||||
|     public: | ||||
|         /**
 | ||||
|         * create c2. | ||||
|         * random fill c2s2 1536 bytes | ||||
|         *  | ||||
|         * // client generate C2, or server valid C2
 | ||||
|         * temp-key = HMACsha256(s1-digest, FPKey, 62) | ||||
|         * c2-digest-data = HMACsha256(c2-random-data, temp-key, 32) | ||||
|         */ | ||||
|         virtual int c2_create(c1s1* s1); | ||||
|          | ||||
|         /**
 | ||||
|         * validate the c2 from client. | ||||
|         */ | ||||
|         virtual int c2_validate(c1s1* s1, bool& is_valid); | ||||
|     public: | ||||
|         /**
 | ||||
|         * create s2. | ||||
|         * random fill c2s2 1536 bytes | ||||
|         *  | ||||
|         * // server generate S2, or client valid S2
 | ||||
|         * temp-key = HMACsha256(c1-digest, FMSKey, 68) | ||||
|         * s2-digest-data = HMACsha256(s2-random-data, temp-key, 32) | ||||
|         */ | ||||
|         virtual int s2_create(c1s1* c1); | ||||
|          | ||||
|         /**
 | ||||
|         * validate the s2 from server. | ||||
|         */ | ||||
|         virtual int s2_validate(c1s1* c1, bool& is_valid); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
| * simple handshake. | ||||
| * user can try complex handshake first,  | ||||
| * rollback to simple handshake if error ERROR_RTMP_TRY_SIMPLE_HS | ||||
| */ | ||||
| class SrsSimpleHandshake | ||||
| { | ||||
| public: | ||||
|     SrsSimpleHandshake(); | ||||
|     virtual ~SrsSimpleHandshake(); | ||||
| public: | ||||
|     /**
 | ||||
|     * simple handshake. | ||||
|     */ | ||||
|     virtual int handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io); | ||||
|     virtual int handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * rtmp complex handshake, | ||||
| * @see also crtmp(crtmpserver) or librtmp, | ||||
| * @see also: http://blog.csdn.net/win_lin/article/details/13006803
 | ||||
| */ | ||||
| class SrsComplexHandshake | ||||
| { | ||||
| public: | ||||
|     SrsComplexHandshake(); | ||||
|     virtual ~SrsComplexHandshake(); | ||||
| public: | ||||
|     /**
 | ||||
|     * complex hanshake. | ||||
|     * @return user must: | ||||
|     *     continue connect app if success, | ||||
|     *     try simple handshake if error is ERROR_RTMP_TRY_SIMPLE_HS, | ||||
|     *     otherwise, disconnect | ||||
|     */ | ||||
|     virtual int handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io); | ||||
|     virtual int handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										73
									
								
								trunk/src/protocol/srs_rtmp_io.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								trunk/src/protocol/srs_rtmp_io.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,73 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include <srs_rtmp_io.hpp> | ||||
| 
 | ||||
| ISrsBufferReader::ISrsBufferReader() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsBufferReader::~ISrsBufferReader() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsBufferWriter::ISrsBufferWriter() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsBufferWriter::~ISrsBufferWriter() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolStatistic::ISrsProtocolStatistic() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolStatistic::~ISrsProtocolStatistic() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolReader::ISrsProtocolReader() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolReader::~ISrsProtocolReader() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolWriter::ISrsProtocolWriter() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolWriter::~ISrsProtocolWriter() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolReaderWriter::ISrsProtocolReaderWriter() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| ISrsProtocolReaderWriter::~ISrsProtocolReaderWriter() | ||||
| { | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										184
									
								
								trunk/src/protocol/srs_rtmp_io.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								trunk/src/protocol/srs_rtmp_io.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,184 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_RTMP_PROTOCOL_IO_HPP | ||||
| #define SRS_RTMP_PROTOCOL_IO_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_io.hpp> | ||||
| */ | ||||
| 
 | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| // for srs-librtmp, @see https://github.com/winlinvip/simple-rtmp-server/issues/213
 | ||||
| #ifndef _WIN32 | ||||
| #include <sys/uio.h> | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
| * the system io reader/writer architecture: | ||||
| +---------------+     +--------------------+      +---------------+ | ||||
| | IBufferReader |     |    IStatistic      |      | IBufferWriter | | ||||
| +---------------+     +--------------------+      +---------------+ | ||||
| | + read()      |     | + get_recv_bytes() |      | + write()     | | ||||
| +------+--------+     | + get_recv_bytes() |      | + writev()    | | ||||
|       / \             +---+--------------+-+      +-------+-------+ | ||||
|        |                 / \            / \              / \ | ||||
|        |                  |              |                | | ||||
| +------+------------------+-+      +-----+----------------+--+ | ||||
| | IProtocolReader           |      | IProtocolWriter         | | ||||
| +---------------------------+      +-------------------------+ | ||||
| | + readfully()             |      | + set_send_timeout()    | | ||||
| | + set_recv_timeout()      |      +-------+-----------------+ | ||||
| +------------+--------------+             / \      | ||||
|             / \                            |    | ||||
|              |                             |  | ||||
|           +--+-----------------------------+-+ | ||||
|           |       IProtocolReaderWriter      | | ||||
|           +----------------------------------+ | ||||
|           | + is_never_timeout()             | | ||||
|           +----------------------------------+ | ||||
| */ | ||||
| 
 | ||||
| /**
 | ||||
| * the reader for the buffer to read from whatever channel. | ||||
| */ | ||||
| class ISrsBufferReader | ||||
| { | ||||
| public: | ||||
|     ISrsBufferReader(); | ||||
|     virtual ~ISrsBufferReader(); | ||||
| // for protocol/amf0/msg-codec
 | ||||
| public: | ||||
|     virtual int read(void* buf, size_t size, ssize_t* nread) = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the writer for the buffer to write to whatever channel. | ||||
| */ | ||||
| class ISrsBufferWriter | ||||
| { | ||||
| public: | ||||
|     ISrsBufferWriter(); | ||||
|     virtual ~ISrsBufferWriter(); | ||||
| // for protocol
 | ||||
| public: | ||||
|     /**
 | ||||
|     * write bytes over writer. | ||||
|     * @nwrite the actual written bytes. NULL to ignore. | ||||
|     */ | ||||
|     virtual int write(void* buf, size_t size, ssize_t* nwrite) = 0; | ||||
|     /**
 | ||||
|     * write iov over writer. | ||||
|     * @nwrite the actual written bytes. NULL to ignore. | ||||
|     */ | ||||
|     virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite) = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * get the statistic of channel. | ||||
| */ | ||||
| class ISrsProtocolStatistic | ||||
| { | ||||
| public: | ||||
|     ISrsProtocolStatistic(); | ||||
|     virtual ~ISrsProtocolStatistic(); | ||||
| // for protocol
 | ||||
| public: | ||||
|     /**
 | ||||
|     * get the total recv bytes over underlay fd. | ||||
|     */ | ||||
|     virtual int64_t get_recv_bytes() = 0; | ||||
|     /**
 | ||||
|     * get the total send bytes over underlay fd. | ||||
|     */ | ||||
|     virtual int64_t get_send_bytes() = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the reader for the protocol to read from whatever channel. | ||||
| */ | ||||
| class ISrsProtocolReader : public virtual ISrsBufferReader, public virtual ISrsProtocolStatistic | ||||
| { | ||||
| public: | ||||
|     ISrsProtocolReader(); | ||||
|     virtual ~ISrsProtocolReader(); | ||||
| // for protocol
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the recv timeout in us, recv will error when timeout. | ||||
|     * @remark, if not set, use ST_UTIME_NO_TIMEOUT, never timeout. | ||||
|     */ | ||||
|     virtual void set_recv_timeout(int64_t timeout_us) = 0; | ||||
|     /**
 | ||||
|     * get the recv timeout in us. | ||||
|     */ | ||||
|     virtual int64_t get_recv_timeout() = 0; | ||||
| // for handshake.
 | ||||
| public: | ||||
|     /**
 | ||||
|     * read specified size bytes of data | ||||
|     * @param nread, the actually read size, NULL to ignore. | ||||
|     */ | ||||
|     virtual int read_fully(void* buf, size_t size, ssize_t* nread) = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the writer for the protocol to write to whatever channel. | ||||
| */ | ||||
| class ISrsProtocolWriter : public virtual ISrsBufferWriter, public virtual ISrsProtocolStatistic | ||||
| { | ||||
| public: | ||||
|     ISrsProtocolWriter(); | ||||
|     virtual ~ISrsProtocolWriter(); | ||||
| // for protocol
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the send timeout in us, send will error when timeout. | ||||
|     * @remark, if not set, use ST_UTIME_NO_TIMEOUT, never timeout. | ||||
|     */ | ||||
|     virtual void set_send_timeout(int64_t timeout_us) = 0; | ||||
|     /**
 | ||||
|     * get the send timeout in us. | ||||
|     */ | ||||
|     virtual int64_t get_send_timeout() = 0; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the reader and writer. | ||||
| */ | ||||
| class ISrsProtocolReaderWriter : public virtual ISrsProtocolReader, public virtual ISrsProtocolWriter | ||||
| { | ||||
| public: | ||||
|     ISrsProtocolReaderWriter(); | ||||
|     virtual ~ISrsProtocolReaderWriter(); | ||||
| // for protocol
 | ||||
| public: | ||||
|     /**
 | ||||
|     * whether the specified timeout_us is never timeout. | ||||
|     */ | ||||
|     virtual bool is_never_timeout(int64_t timeout_us) = 0; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										65
									
								
								trunk/src/protocol/srs_rtmp_msg_array.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								trunk/src/protocol/srs_rtmp_msg_array.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include <srs_rtmp_msg_array.hpp> | ||||
| 
 | ||||
| #include <srs_rtmp_stack.hpp> | ||||
| 
 | ||||
| SrsMessageArray::SrsMessageArray(int max_msgs) | ||||
| { | ||||
|     srs_assert(max_msgs > 0); | ||||
|      | ||||
|     msgs = new SrsSharedPtrMessage*[max_msgs]; | ||||
|     max = max_msgs; | ||||
|      | ||||
|     zero(max_msgs); | ||||
| } | ||||
| 
 | ||||
| SrsMessageArray::~SrsMessageArray() | ||||
| { | ||||
|     // we just free the msgs itself,
 | ||||
|     // both delete and delete[] is ok,
 | ||||
|     // for each msg in msgs is already freed by send_and_free_messages.
 | ||||
|     srs_freep(msgs); | ||||
| } | ||||
| 
 | ||||
| void SrsMessageArray::free(int count) | ||||
| { | ||||
|     // initialize
 | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         SrsSharedPtrMessage* msg = msgs[i]; | ||||
|         srs_freep(msg); | ||||
|          | ||||
|         msgs[i] = NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void SrsMessageArray::zero(int count) | ||||
| { | ||||
|     // initialize
 | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         msgs[i] = NULL; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										76
									
								
								trunk/src/protocol/srs_rtmp_msg_array.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								trunk/src/protocol/srs_rtmp_msg_array.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,76 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_RTMP_PROTOCOL_MSG_ARRAY_HPP | ||||
| #define SRS_RTMP_PROTOCOL_MSG_ARRAY_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_msg_array.hpp> | ||||
| */ | ||||
| 
 | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| class SrsSharedPtrMessage; | ||||
| 
 | ||||
| /**
 | ||||
| * the class to auto free the shared ptr message array. | ||||
| * when need to get some messages, for instance, from Consumer queue, | ||||
| * create a message array, whose msgs can used to accept the msgs, | ||||
| * then send each message and set to NULL. | ||||
| * | ||||
| * @remark: user must free all msgs in array, for the SRS2.0 protocol stack | ||||
| *       provides an api to send messages, @see send_and_free_messages | ||||
| */ | ||||
| class SrsMessageArray | ||||
| { | ||||
| public: | ||||
|     /**
 | ||||
|     * when user already send the msg in msgs, please set to NULL, | ||||
|     * for instance, msg= msgs.msgs[i], msgs.msgs[i]=NULL, send(msg), | ||||
|     * where send(msg) will always send and free it. | ||||
|     */ | ||||
|     SrsSharedPtrMessage** msgs; | ||||
|     int max; | ||||
| public: | ||||
|     /**
 | ||||
|     * create msg array, initialize array to NULL ptrs. | ||||
|     */ | ||||
|     SrsMessageArray(int max_msgs); | ||||
|     /**
 | ||||
|     * free the msgs not sent out(not NULL). | ||||
|     */ | ||||
|     virtual ~SrsMessageArray(); | ||||
| public: | ||||
|     /**
 | ||||
|     * free specified count of messages. | ||||
|     */ | ||||
|     virtual void free(int count); | ||||
| private: | ||||
|     /**
 | ||||
|     * zero initialize the message array. | ||||
|     */ | ||||
|     virtual void zero(int count); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										1516
									
								
								trunk/src/protocol/srs_rtmp_sdk.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1516
									
								
								trunk/src/protocol/srs_rtmp_sdk.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										541
									
								
								trunk/src/protocol/srs_rtmp_sdk.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										541
									
								
								trunk/src/protocol/srs_rtmp_sdk.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,541 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_RTMP_PROTOCOL_RTMP_HPP | ||||
| #define SRS_RTMP_PROTOCOL_RTMP_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_sdk.hpp> | ||||
| */ | ||||
| 
 | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include <srs_rtmp_stack.hpp> | ||||
| #include <srs_core_performance.hpp> | ||||
| 
 | ||||
| class SrsProtocol; | ||||
| class ISrsProtocolReaderWriter; | ||||
| class SrsCommonMessage; | ||||
| class SrsCreateStreamPacket; | ||||
| class SrsFMLEStartPacket; | ||||
| class SrsPublishPacket; | ||||
| class SrsOnMetaDataPacket; | ||||
| class SrsPlayPacket; | ||||
| class SrsCommonMessage; | ||||
| class SrsPacket; | ||||
| class SrsAmf0Object; | ||||
| class IMergeReadHandler; | ||||
| 
 | ||||
| /**
 | ||||
| * the original request from client. | ||||
| */ | ||||
| class SrsRequest | ||||
| { | ||||
| public: | ||||
|     // client ip.
 | ||||
|     std::string ip; | ||||
| public: | ||||
|     /**
 | ||||
|     * tcUrl: rtmp://request_vhost:port/app/stream
 | ||||
|     * support pass vhost in query string, such as: | ||||
|     *    rtmp://ip:port/app?vhost=request_vhost/stream
 | ||||
|     *    rtmp://ip:port/app...vhost...request_vhost/stream
 | ||||
|     */ | ||||
|     std::string tcUrl; | ||||
|     std::string pageUrl; | ||||
|     std::string swfUrl; | ||||
|     double objectEncoding; | ||||
| // data discovery from request.
 | ||||
| public: | ||||
|     // discovery from tcUrl and play/publish.
 | ||||
|     std::string schema; | ||||
|     // the vhost in tcUrl.
 | ||||
|     std::string vhost; | ||||
|     // the host in tcUrl.
 | ||||
|     std::string host; | ||||
|     // the port in tcUrl.
 | ||||
|     std::string port; | ||||
|     // the app in tcUrl, without param.
 | ||||
|     std::string app; | ||||
|     // the param in tcUrl(app).
 | ||||
|     std::string param; | ||||
|     // the stream in play/publish
 | ||||
|     std::string stream; | ||||
|     // for play live stream, 
 | ||||
|     // used to specified the stop when exceed the duration.
 | ||||
|     // @see https://github.com/winlinvip/simple-rtmp-server/issues/45
 | ||||
|     // in ms.
 | ||||
|     double duration; | ||||
|     // the token in the connect request,
 | ||||
|     // used for edge traverse to origin authentication,
 | ||||
|     // @see https://github.com/winlinvip/simple-rtmp-server/issues/104
 | ||||
|     SrsAmf0Object* args; | ||||
| public: | ||||
|     SrsRequest(); | ||||
|     virtual ~SrsRequest(); | ||||
| public: | ||||
|     /**
 | ||||
|     * deep copy the request, for source to use it to support reload, | ||||
|     * for when initialize the source, the request is valid, | ||||
|     * when reload it, the request maybe invalid, so need to copy it. | ||||
|     */ | ||||
|     virtual SrsRequest* copy(); | ||||
|     /**
 | ||||
|     * update the auth info of request, | ||||
|     * to keep the current request ptr is ok, | ||||
|     * for many components use the ptr of request. | ||||
|     */ | ||||
|     virtual void update_auth(SrsRequest* req); | ||||
|     /**
 | ||||
|     * get the stream identify, vhost/app/stream. | ||||
|     */ | ||||
|     virtual std::string get_stream_url(); | ||||
|     /**
 | ||||
|     * strip url, user must strip when update the url. | ||||
|     */ | ||||
|     virtual void strip(); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the response to client. | ||||
| */ | ||||
| class SrsResponse | ||||
| { | ||||
| public: | ||||
|     /**
 | ||||
|     * the stream id to response client createStream. | ||||
|     */ | ||||
|     int stream_id; | ||||
| public: | ||||
|     SrsResponse(); | ||||
|     virtual ~SrsResponse(); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the rtmp client type. | ||||
| */ | ||||
| enum SrsRtmpConnType | ||||
| { | ||||
|     SrsRtmpConnUnknown, | ||||
|     SrsRtmpConnPlay, | ||||
|     SrsRtmpConnFMLEPublish, | ||||
|     SrsRtmpConnFlashPublish, | ||||
| }; | ||||
| std::string srs_client_type_string(SrsRtmpConnType type); | ||||
| 
 | ||||
| /**
 | ||||
| * store the handshake bytes,  | ||||
| * for smart switch between complex and simple handshake. | ||||
| */ | ||||
| class SrsHandshakeBytes | ||||
| { | ||||
| public: | ||||
|     // [1+1536]
 | ||||
|     char* c0c1; | ||||
|     // [1+1536+1536]
 | ||||
|     char* s0s1s2; | ||||
|     // [1536]
 | ||||
|     char* c2; | ||||
| public: | ||||
|     SrsHandshakeBytes(); | ||||
|     virtual ~SrsHandshakeBytes(); | ||||
| public: | ||||
|     virtual int read_c0c1(ISrsProtocolReaderWriter* io); | ||||
|     virtual int read_s0s1s2(ISrsProtocolReaderWriter* io); | ||||
|     virtual int read_c2(ISrsProtocolReaderWriter* io); | ||||
|     virtual int create_c0c1(); | ||||
|     virtual int create_s0s1s2(const char* c1 = NULL); | ||||
|     virtual int create_c2(); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * implements the client role protocol. | ||||
| */ | ||||
| class SrsRtmpClient | ||||
| { | ||||
| private: | ||||
|     SrsHandshakeBytes* hs_bytes; | ||||
| protected: | ||||
|     SrsProtocol* protocol; | ||||
|     ISrsProtocolReaderWriter* io; | ||||
| public: | ||||
|     SrsRtmpClient(ISrsProtocolReaderWriter* skt); | ||||
|     virtual ~SrsRtmpClient(); | ||||
| // protocol methods proxy
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the recv timeout in us. | ||||
|     * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. | ||||
|     */ | ||||
|     virtual void set_recv_timeout(int64_t timeout_us); | ||||
|     /**
 | ||||
|     * set the send timeout in us. | ||||
|     * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. | ||||
|     */ | ||||
|     virtual void set_send_timeout(int64_t timeout_us); | ||||
|     /**
 | ||||
|     * get recv/send bytes. | ||||
|     */ | ||||
|     virtual int64_t get_recv_bytes(); | ||||
|     virtual int64_t get_send_bytes(); | ||||
|     /**
 | ||||
|     * recv a RTMP message, which is bytes oriented. | ||||
|     * user can use decode_message to get the decoded RTMP packet. | ||||
|     * @param pmsg, set the received message,  | ||||
|     *       always NULL if error,  | ||||
|     *       NULL for unknown packet but return success. | ||||
|     *       never NULL if decode success. | ||||
|     * @remark, drop message when msg is empty or payload length is empty. | ||||
|     */ | ||||
|     virtual int recv_message(SrsCommonMessage** pmsg); | ||||
|     /**
 | ||||
|     * decode bytes oriented RTMP message to RTMP packet, | ||||
|     * @param ppacket, output decoded packet,  | ||||
|     *       always NULL if error, never NULL if success. | ||||
|     * @return error when unknown packet, error when decode failed. | ||||
|     */ | ||||
|     virtual int decode_message(SrsCommonMessage* msg, SrsPacket** ppacket); | ||||
|     /**
 | ||||
|     * send the RTMP message and always free it. | ||||
|     * user must never free or use the msg after this method, | ||||
|     * for it will always free the msg. | ||||
|     * @param msg, the msg to send out, never be NULL. | ||||
|     * @param stream_id, the stream id of packet to send over, 0 for control message. | ||||
|     */ | ||||
|     virtual int send_and_free_message(SrsSharedPtrMessage* msg, int stream_id); | ||||
|     /**
 | ||||
|     * send the RTMP message and always free it. | ||||
|     * user must never free or use the msg after this method, | ||||
|     * for it will always free the msg. | ||||
|     * @param msgs, the msgs to send out, never be NULL. | ||||
|     * @param nb_msgs, the size of msgs to send out. | ||||
|     * @param stream_id, the stream id of packet to send over, 0 for control message. | ||||
|     */ | ||||
|     virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); | ||||
|     /**
 | ||||
|     * send the RTMP packet and always free it. | ||||
|     * user must never free or use the packet after this method, | ||||
|     * for it will always free the packet. | ||||
|     * @param packet, the packet to send out, never be NULL. | ||||
|     * @param stream_id, the stream id of packet to send over, 0 for control message. | ||||
|     */ | ||||
|     virtual int send_and_free_packet(SrsPacket* packet, int stream_id); | ||||
| public: | ||||
|     /**
 | ||||
|     * handshake with server, try complex, then simple handshake. | ||||
|     */ | ||||
|     virtual int handshake(); | ||||
|     /**
 | ||||
|     * only use simple handshake | ||||
|     */ | ||||
|     virtual int simple_handshake(); | ||||
|     /**
 | ||||
|     * only use complex handshake | ||||
|     */ | ||||
|     virtual int complex_handshake(); | ||||
|     /**
 | ||||
|     * set req to use the original request of client: | ||||
|     *      pageUrl and swfUrl for refer antisuck. | ||||
|     *      args for edge to origin traverse auth, @see SrsRequest.args | ||||
|     */ | ||||
|     virtual int connect_app(std::string app, std::string tc_url,  | ||||
|         SrsRequest* req, bool debug_srs_upnode); | ||||
|     /**
 | ||||
|     * connect to server, get the debug srs info. | ||||
|     *  | ||||
|     * @param app, the app to connect at. | ||||
|     * @param tc_url, the tcUrl to connect at. | ||||
|     * @param req, the optional req object, use the swfUrl/pageUrl if specified. NULL to ignore. | ||||
|     *  | ||||
|     * SRS debug info: | ||||
|     * @param srs_server_ip, debug info, server ip client connected at. | ||||
|     * @param srs_server, server info. | ||||
|     * @param srs_primary, primary authors. | ||||
|     * @param srs_authors, authors. | ||||
|     * @param srs_id, int, debug info, client id in server log. | ||||
|     * @param srs_pid, int, debug info, server pid in log. | ||||
|     */ | ||||
|     virtual int connect_app2( | ||||
|         std::string app, std::string tc_url, SrsRequest* req, bool debug_srs_upnode, | ||||
|         std::string& srs_server_ip, std::string& srs_server, std::string& srs_primary,  | ||||
|         std::string& srs_authors, std::string& srs_version, int& srs_id,  | ||||
|         int& srs_pid | ||||
|     ); | ||||
|     /**
 | ||||
|     * create a stream, then play/publish data over this stream. | ||||
|     */ | ||||
|     virtual int create_stream(int& stream_id); | ||||
|     /**
 | ||||
|     * start play stream. | ||||
|     */ | ||||
|     virtual int play(std::string stream, int stream_id); | ||||
|     /**
 | ||||
|     * start publish stream. use flash publish workflow: | ||||
|     *       connect-app => create-stream => flash-publish | ||||
|     */ | ||||
|     virtual int publish(std::string stream, int stream_id); | ||||
|     /**
 | ||||
|     * start publish stream. use FMLE publish workflow: | ||||
|     *       connect-app => FMLE publish | ||||
|     */ | ||||
|     virtual int fmle_publish(std::string stream, int& stream_id); | ||||
| public: | ||||
|     /**
 | ||||
|     * expect a specified message, drop others util got specified one. | ||||
|     * @pmsg, user must free it. NULL if not success. | ||||
|     * @ppacket, store in the pmsg, user must never free it. NULL if not success. | ||||
|     * @remark, only when success, user can use and must free the pmsg/ppacket. | ||||
|     * for example: | ||||
|              SrsCommonMessage* msg = NULL; | ||||
|             SrsConnectAppResPacket* pkt = NULL; | ||||
|             if ((ret = srs_rtmp_expect_message<SrsConnectAppResPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) { | ||||
|                 return ret; | ||||
|             } | ||||
|             // use pkt
 | ||||
|     * user should never recv message and convert it, use this method instead. | ||||
|     * if need to set timeout, use set timeout of SrsProtocol. | ||||
|     */ | ||||
|     template<class T> | ||||
|     int expect_message(SrsCommonMessage** pmsg, T** ppacket) | ||||
|     { | ||||
|         return protocol->expect_message<T>(pmsg, ppacket); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| * the rtmp provices rtmp-command-protocol services, | ||||
| * a high level protocol, media stream oriented services, | ||||
| * such as connect to vhost/app, play stream, get audio/video data. | ||||
| */ | ||||
| class SrsRtmpServer | ||||
| { | ||||
| private: | ||||
|     SrsHandshakeBytes* hs_bytes; | ||||
|     SrsProtocol* protocol; | ||||
|     ISrsProtocolReaderWriter* io; | ||||
| public: | ||||
|     SrsRtmpServer(ISrsProtocolReaderWriter* skt); | ||||
|     virtual ~SrsRtmpServer(); | ||||
| // protocol methods proxy
 | ||||
| public: | ||||
|     /**
 | ||||
|     * set the auto response message when recv for protocol stack. | ||||
|     * @param v, whether auto response message when recv message. | ||||
|     * @see: https://github.com/winlinvip/simple-rtmp-server/issues/217
 | ||||
|     */ | ||||
|     virtual void set_auto_response(bool v); | ||||
| #ifdef SRS_PERF_MERGED_READ | ||||
|     /**
 | ||||
|     * to improve read performance, merge some packets then read, | ||||
|     * when it on and read small bytes, we sleep to wait more data., | ||||
|     * that is, we merge some data to read together. | ||||
|     * @param v true to ename merged read. | ||||
|     * @param handler the handler when merge read is enabled. | ||||
|     * @see https://github.com/winlinvip/simple-rtmp-server/issues/241
 | ||||
|     */ | ||||
|     virtual void set_merge_read(bool v, IMergeReadHandler* handler); | ||||
|     /**
 | ||||
|     * create buffer with specifeid size. | ||||
|     * @param buffer the size of buffer. | ||||
|     * @remark when MR(SRS_PERF_MERGED_READ) disabled, always set to 8K. | ||||
|     * @remark when buffer changed, the previous ptr maybe invalid. | ||||
|     * @see https://github.com/winlinvip/simple-rtmp-server/issues/241
 | ||||
|     */ | ||||
|     virtual void set_recv_buffer(int buffer_size); | ||||
| #endif | ||||
|     /**
 | ||||
|     * set/get the recv timeout in us. | ||||
|     * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. | ||||
|     */ | ||||
|     virtual void set_recv_timeout(int64_t timeout_us); | ||||
|     virtual int64_t get_recv_timeout(); | ||||
|     /**
 | ||||
|     * set/get the send timeout in us. | ||||
|     * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. | ||||
|     */ | ||||
|     virtual void set_send_timeout(int64_t timeout_us); | ||||
|     virtual int64_t get_send_timeout(); | ||||
|     /**
 | ||||
|     * get recv/send bytes. | ||||
|     */ | ||||
|     virtual int64_t get_recv_bytes(); | ||||
|     virtual int64_t get_send_bytes(); | ||||
|     /**
 | ||||
|     * recv a RTMP message, which is bytes oriented. | ||||
|     * user can use decode_message to get the decoded RTMP packet. | ||||
|     * @param pmsg, set the received message,  | ||||
|     *       always NULL if error,  | ||||
|     *       NULL for unknown packet but return success. | ||||
|     *       never NULL if decode success. | ||||
|     * @remark, drop message when msg is empty or payload length is empty. | ||||
|     */ | ||||
|     virtual int recv_message(SrsCommonMessage** pmsg); | ||||
|     /**
 | ||||
|     * decode bytes oriented RTMP message to RTMP packet, | ||||
|     * @param ppacket, output decoded packet,  | ||||
|     *       always NULL if error, never NULL if success. | ||||
|     * @return error when unknown packet, error when decode failed. | ||||
|     */ | ||||
|     virtual int decode_message(SrsCommonMessage* msg, SrsPacket** ppacket); | ||||
|     /**
 | ||||
|     * send the RTMP message and always free it. | ||||
|     * user must never free or use the msg after this method, | ||||
|     * for it will always free the msg. | ||||
|     * @param msg, the msg to send out, never be NULL. | ||||
|     * @param stream_id, the stream id of packet to send over, 0 for control message. | ||||
|     */ | ||||
|     virtual int send_and_free_message(SrsSharedPtrMessage* msg, int stream_id); | ||||
|     /**
 | ||||
|     * send the RTMP message and always free it. | ||||
|     * user must never free or use the msg after this method, | ||||
|     * for it will always free the msg. | ||||
|     * @param msgs, the msgs to send out, never be NULL. | ||||
|     * @param nb_msgs, the size of msgs to send out. | ||||
|     * @param stream_id, the stream id of packet to send over, 0 for control message. | ||||
|     * | ||||
|     * @remark performance issue, to support 6k+ 250kbps client, | ||||
|     *       @see https://github.com/winlinvip/simple-rtmp-server/issues/194
 | ||||
|     */ | ||||
|     virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); | ||||
|     /**
 | ||||
|     * send the RTMP packet and always free it. | ||||
|     * user must never free or use the packet after this method, | ||||
|     * for it will always free the packet. | ||||
|     * @param packet, the packet to send out, never be NULL. | ||||
|     * @param stream_id, the stream id of packet to send over, 0 for control message. | ||||
|     */ | ||||
|     virtual int send_and_free_packet(SrsPacket* packet, int stream_id); | ||||
| public: | ||||
|     /**
 | ||||
|     * handshake with client, try complex then simple. | ||||
|     */ | ||||
|     virtual int handshake(); | ||||
|     /**
 | ||||
|     * do connect app with client, to discovery tcUrl. | ||||
|     */ | ||||
|     virtual int connect_app(SrsRequest* req); | ||||
|     /**
 | ||||
|     * set ack size to client, client will send ack-size for each ack window | ||||
|     */ | ||||
|     virtual int set_window_ack_size(int ack_size); | ||||
|     /**
 | ||||
|     * @type: The sender can mark this message hard (0), soft (1), or dynamic (2) | ||||
|     * using the Limit type field. | ||||
|     */ | ||||
|     virtual int set_peer_bandwidth(int bandwidth, int type); | ||||
|     /**
 | ||||
|     * @param server_ip the ip of server. | ||||
|     */ | ||||
|     virtual int response_connect_app(SrsRequest* req, const char* server_ip = NULL); | ||||
|     /**
 | ||||
|     * reject the connect app request. | ||||
|     */ | ||||
|     virtual void response_connect_reject(SrsRequest* req, const char* desc); | ||||
|     /**
 | ||||
|     * response client the onBWDone message. | ||||
|     */ | ||||
|     virtual int on_bw_done(); | ||||
|     /**
 | ||||
|     * recv some message to identify the client. | ||||
|     * @stream_id, client will createStream to play or publish by flash,  | ||||
|     *         the stream_id used to response the createStream request. | ||||
|     * @type, output the client type. | ||||
|     * @stream_name, output the client publish/play stream name. @see: SrsRequest.stream | ||||
|     * @duration, output the play client duration. @see: SrsRequest.duration | ||||
|     */ | ||||
|     virtual int identify_client(int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration); | ||||
|     /**
 | ||||
|     * set the chunk size when client type identified. | ||||
|     */ | ||||
|     virtual int set_chunk_size(int chunk_size); | ||||
|     /**
 | ||||
|     * when client type is play, response with packets: | ||||
|     * StreamBegin,  | ||||
|     * onStatus(NetStream.Play.Reset), onStatus(NetStream.Play.Start)., | ||||
|     * |RtmpSampleAccess(false, false), | ||||
|     * onStatus(NetStream.Data.Start). | ||||
|     */ | ||||
|     virtual int start_play(int stream_id); | ||||
|     /**
 | ||||
|     * when client(type is play) send pause message, | ||||
|     * if is_pause, response the following packets: | ||||
|     *     onStatus(NetStream.Pause.Notify) | ||||
|     *     StreamEOF | ||||
|     * if not is_pause, response the following packets: | ||||
|     *     onStatus(NetStream.Unpause.Notify) | ||||
|     *     StreamBegin | ||||
|     */ | ||||
|     virtual int on_play_client_pause(int stream_id, bool is_pause); | ||||
|     /**
 | ||||
|     * when client type is publish, response with packets: | ||||
|     * releaseStream response | ||||
|     * FCPublish | ||||
|     * FCPublish response | ||||
|     * createStream response | ||||
|     * onFCPublish(NetStream.Publish.Start) | ||||
|     * onStatus(NetStream.Publish.Start) | ||||
|     */ | ||||
|     virtual int start_fmle_publish(int stream_id); | ||||
|     /**
 | ||||
|     * process the FMLE unpublish event. | ||||
|     * @unpublish_tid the unpublish request transaction id. | ||||
|     */ | ||||
|     virtual int fmle_unpublish(int stream_id, double unpublish_tid); | ||||
|     /**
 | ||||
|     * when client type is publish, response with packets: | ||||
|     * onStatus(NetStream.Publish.Start) | ||||
|     */ | ||||
|     virtual int start_flash_publish(int stream_id); | ||||
| public: | ||||
|     /**
 | ||||
|     * expect a specified message, drop others util got specified one. | ||||
|     * @pmsg, user must free it. NULL if not success. | ||||
|     * @ppacket, store in the pmsg, user must never free it. NULL if not success. | ||||
|     * @remark, only when success, user can use and must free the pmsg/ppacket. | ||||
|     * for example: | ||||
|              SrsCommonMessage* msg = NULL; | ||||
|             SrsConnectAppResPacket* pkt = NULL; | ||||
|             if ((ret = srs_rtmp_expect_message<SrsConnectAppResPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) { | ||||
|                 return ret; | ||||
|             } | ||||
|             // use pkt
 | ||||
|     * user should never recv message and convert it, use this method instead. | ||||
|     * if need to set timeout, use set timeout of SrsProtocol. | ||||
|     */ | ||||
|     template<class T> | ||||
|     int expect_message(SrsCommonMessage** pmsg, T** ppacket) | ||||
|     { | ||||
|         return protocol->expect_message<T>(pmsg, ppacket); | ||||
|     } | ||||
| private: | ||||
|     virtual int identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration); | ||||
|     virtual int identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name); | ||||
|     virtual int identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name); | ||||
| private: | ||||
|     virtual int identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, std::string& stream_name, double& duration); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
							
								
								
									
										4137
									
								
								trunk/src/protocol/srs_rtmp_stack.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4137
									
								
								trunk/src/protocol/srs_rtmp_stack.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1740
									
								
								trunk/src/protocol/srs_rtmp_stack.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1740
									
								
								trunk/src/protocol/srs_rtmp_stack.hpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										289
									
								
								trunk/src/protocol/srs_rtmp_utility.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								trunk/src/protocol/srs_rtmp_utility.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,289 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #include <srs_rtmp_utility.hpp> | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| using namespace std; | ||||
| 
 | ||||
| #include <srs_kernel_log.hpp> | ||||
| #include <srs_kernel_utility.hpp> | ||||
| #include <srs_kernel_stream.hpp> | ||||
| #include <srs_rtmp_stack.hpp> | ||||
| 
 | ||||
| void srs_discovery_tc_url( | ||||
|     string tcUrl,  | ||||
|     string& schema, string& host, string& vhost,  | ||||
|     string& app, string& port, std::string& param | ||||
| ) { | ||||
|     size_t pos = std::string::npos; | ||||
|     std::string url = tcUrl; | ||||
|      | ||||
|     if ((pos = url.find("://")) != std::string::npos) { | ||||
|         schema = url.substr(0, pos); | ||||
|         url = url.substr(schema.length() + 3); | ||||
|         srs_info("discovery schema=%s", schema.c_str()); | ||||
|     } | ||||
|      | ||||
|     if ((pos = url.find("/")) != std::string::npos) { | ||||
|         host = url.substr(0, pos); | ||||
|         url = url.substr(host.length() + 1); | ||||
|         srs_info("discovery host=%s", host.c_str()); | ||||
|     } | ||||
| 
 | ||||
|     port = SRS_CONSTS_RTMP_DEFAULT_PORT; | ||||
|     if ((pos = host.find(":")) != std::string::npos) { | ||||
|         port = host.substr(pos + 1); | ||||
|         host = host.substr(0, pos); | ||||
|         srs_info("discovery host=%s, port=%s", host.c_str(), port.c_str()); | ||||
|     } | ||||
|      | ||||
|     app = url; | ||||
|     vhost = host; | ||||
|     srs_vhost_resolve(vhost, app, param); | ||||
| } | ||||
| 
 | ||||
| void srs_vhost_resolve(string& vhost, string& app, string& param) | ||||
| { | ||||
|     // get original param
 | ||||
|     size_t pos = 0; | ||||
|     if ((pos = app.find("?")) != std::string::npos) { | ||||
|         param = app.substr(pos); | ||||
|     } | ||||
|      | ||||
|     // filter tcUrl
 | ||||
|     app = srs_string_replace(app, ",", "?"); | ||||
|     app = srs_string_replace(app, "...", "?"); | ||||
|     app = srs_string_replace(app, "&&", "?"); | ||||
|     app = srs_string_replace(app, "=", "?"); | ||||
|      | ||||
|     if ((pos = app.find("?")) == std::string::npos) { | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     std::string query = app.substr(pos + 1); | ||||
|     app = app.substr(0, pos); | ||||
|      | ||||
|     if ((pos = query.find("vhost?")) != std::string::npos) { | ||||
|         query = query.substr(pos + 6); | ||||
|         if (!query.empty()) { | ||||
|             vhost = query; | ||||
|         } | ||||
|         if ((pos = vhost.find("?")) != std::string::npos) { | ||||
|             vhost = vhost.substr(0, pos); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void srs_random_generate(char* bytes, int size) | ||||
| { | ||||
|     static bool _random_initialized = false; | ||||
|     if (!_random_initialized) { | ||||
|         srand(0); | ||||
|         _random_initialized = true; | ||||
|         srs_trace("srand initialized the random."); | ||||
|     } | ||||
|      | ||||
|     for (int i = 0; i < size; i++) { | ||||
|         // the common value in [0x0f, 0xf0]
 | ||||
|         bytes[i] = 0x0f + (rand() % (256 - 0x0f - 0x0f)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| string srs_generate_tc_url(string ip, string vhost, string app, string port, string param) | ||||
| { | ||||
|     string tcUrl = "rtmp://"; | ||||
|      | ||||
|     if (vhost == SRS_CONSTS_RTMP_DEFAULT_VHOST) { | ||||
|         tcUrl += ip; | ||||
|     } else { | ||||
|         tcUrl += vhost; | ||||
|     } | ||||
|      | ||||
|     if (port != SRS_CONSTS_RTMP_DEFAULT_PORT) { | ||||
|         tcUrl += ":"; | ||||
|         tcUrl += port; | ||||
|     } | ||||
|      | ||||
|     tcUrl += "/"; | ||||
|     tcUrl += app; | ||||
|     tcUrl += param; | ||||
|      | ||||
|     return tcUrl; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| * compare the memory in bytes. | ||||
| */ | ||||
| bool srs_bytes_equals(void* pa, void* pb, int size) | ||||
| { | ||||
|     u_int8_t* a = (u_int8_t*)pa; | ||||
|     u_int8_t* b = (u_int8_t*)pb; | ||||
|      | ||||
|     if (!a && !b) { | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|     if (!a || !b) { | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     for(int i = 0; i < size; i++){ | ||||
|         if(a[i] != b[i]){ | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| int srs_chunk_header_c0( | ||||
|     int perfer_cid, u_int32_t timestamp, int32_t payload_length, | ||||
|     int8_t message_type, int32_t stream_id, | ||||
|     char* cache, int nb_cache | ||||
| ) | ||||
| { | ||||
|     // to directly set the field.
 | ||||
|     char* pp = NULL; | ||||
|      | ||||
|     // generate the header.
 | ||||
|     char* p = cache; | ||||
|      | ||||
|     // no header.
 | ||||
|     if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE) { | ||||
|         return 0; | ||||
|     } | ||||
|      | ||||
|     // write new chunk stream header, fmt is 0
 | ||||
|     *p++ = 0x00 | (perfer_cid & 0x3F); | ||||
|      | ||||
|     // chunk message header, 11 bytes
 | ||||
|     // timestamp, 3bytes, big-endian
 | ||||
|     if (timestamp < RTMP_EXTENDED_TIMESTAMP) { | ||||
|         pp = (char*)×tamp; | ||||
|         *p++ = pp[2]; | ||||
|         *p++ = pp[1]; | ||||
|         *p++ = pp[0]; | ||||
|     } else { | ||||
|         *p++ = 0xFF; | ||||
|         *p++ = 0xFF; | ||||
|         *p++ = 0xFF; | ||||
|     } | ||||
|      | ||||
|     // message_length, 3bytes, big-endian
 | ||||
|     pp = (char*)&payload_length; | ||||
|     *p++ = pp[2]; | ||||
|     *p++ = pp[1]; | ||||
|     *p++ = pp[0]; | ||||
|      | ||||
|     // message_type, 1bytes
 | ||||
|     *p++ = message_type; | ||||
|      | ||||
|     // stream_id, 4bytes, little-endian
 | ||||
|     pp = (char*)&stream_id; | ||||
|     *p++ = pp[0]; | ||||
|     *p++ = pp[1]; | ||||
|     *p++ = pp[2]; | ||||
|     *p++ = pp[3]; | ||||
|      | ||||
|     // for c0
 | ||||
|     // chunk extended timestamp header, 0 or 4 bytes, big-endian
 | ||||
|     // 
 | ||||
|     // for c3:
 | ||||
|     // chunk extended timestamp header, 0 or 4 bytes, big-endian
 | ||||
|     // 6.1.3. Extended Timestamp
 | ||||
|     // This field is transmitted only when the normal time stamp in the
 | ||||
|     // chunk message header is set to 0x00ffffff. If normal time stamp is
 | ||||
|     // set to any value less than 0x00ffffff, this field MUST NOT be
 | ||||
|     // present. This field MUST NOT be present if the timestamp field is not
 | ||||
|     // present. Type 3 chunks MUST NOT have this field.
 | ||||
|     // adobe changed for Type3 chunk:
 | ||||
|     //        FMLE always sendout the extended-timestamp,
 | ||||
|     //        must send the extended-timestamp to FMS,
 | ||||
|     //        must send the extended-timestamp to flash-player.
 | ||||
|     // @see: ngx_rtmp_prepare_message
 | ||||
|     // @see: http://blog.csdn.net/win_lin/article/details/13363699
 | ||||
|     // TODO: FIXME: extract to outer.
 | ||||
|     if (timestamp >= RTMP_EXTENDED_TIMESTAMP) { | ||||
|         pp = (char*)×tamp; | ||||
|         *p++ = pp[3]; | ||||
|         *p++ = pp[2]; | ||||
|         *p++ = pp[1]; | ||||
|         *p++ = pp[0]; | ||||
|     } | ||||
|      | ||||
|     // always has header
 | ||||
|     return p - cache; | ||||
| } | ||||
| 
 | ||||
| int srs_chunk_header_c3( | ||||
|     int perfer_cid, u_int32_t timestamp,  | ||||
|     char* cache, int nb_cache | ||||
| ) | ||||
| { | ||||
|     // to directly set the field.
 | ||||
|     char* pp = NULL; | ||||
|      | ||||
|     // generate the header.
 | ||||
|     char* p = cache; | ||||
|      | ||||
|     // no header.
 | ||||
|     if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     // write no message header chunk stream, fmt is 3
 | ||||
|     // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,
 | ||||
|     // SRS will rollback to 1B chunk header.
 | ||||
|     *p++ = 0xC0 | (perfer_cid & 0x3F); | ||||
|      | ||||
|     // for c0
 | ||||
|     // chunk extended timestamp header, 0 or 4 bytes, big-endian
 | ||||
|     // 
 | ||||
|     // for c3:
 | ||||
|     // chunk extended timestamp header, 0 or 4 bytes, big-endian
 | ||||
|     // 6.1.3. Extended Timestamp
 | ||||
|     // This field is transmitted only when the normal time stamp in the
 | ||||
|     // chunk message header is set to 0x00ffffff. If normal time stamp is
 | ||||
|     // set to any value less than 0x00ffffff, this field MUST NOT be
 | ||||
|     // present. This field MUST NOT be present if the timestamp field is not
 | ||||
|     // present. Type 3 chunks MUST NOT have this field.
 | ||||
|     // adobe changed for Type3 chunk:
 | ||||
|     //        FMLE always sendout the extended-timestamp,
 | ||||
|     //        must send the extended-timestamp to FMS,
 | ||||
|     //        must send the extended-timestamp to flash-player.
 | ||||
|     // @see: ngx_rtmp_prepare_message
 | ||||
|     // @see: http://blog.csdn.net/win_lin/article/details/13363699
 | ||||
|     // TODO: FIXME: extract to outer.
 | ||||
|     if (timestamp >= RTMP_EXTENDED_TIMESTAMP) { | ||||
|         pp = (char*)×tamp; | ||||
|         *p++ = pp[3]; | ||||
|         *p++ = pp[2]; | ||||
|         *p++ = pp[1]; | ||||
|         *p++ = pp[0]; | ||||
|     } | ||||
|      | ||||
|     // always has header
 | ||||
|     return p - cache; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										114
									
								
								trunk/src/protocol/srs_rtmp_utility.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								trunk/src/protocol/srs_rtmp_utility.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,114 @@ | |||
| /*
 | ||||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2013-2015 winlin | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||||
| this software and associated documentation files (the "Software"), to deal in | ||||
| the Software without restriction, including without limitation the rights to | ||||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||||
| the Software, and to permit persons to whom the Software is furnished to do so, | ||||
| subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||||
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||||
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||||
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||||
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||
| */ | ||||
| 
 | ||||
| #ifndef SRS_RTMP_PROTOCOL_CONSTS_HPP | ||||
| #define SRS_RTMP_PROTOCOL_CONSTS_HPP | ||||
| 
 | ||||
| /*
 | ||||
| #include <srs_rtmp_utility.hpp> | ||||
| */ | ||||
| #include <srs_core.hpp> | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include <srs_kernel_consts.hpp> | ||||
| 
 | ||||
| class SrsMessageHeader; | ||||
| 
 | ||||
| /**
 | ||||
| * parse the tcUrl, output the schema, host, vhost, app and port. | ||||
| * @param tcUrl, the input tcUrl, for example,  | ||||
| *       rtmp://192.168.1.10:19350/live?vhost=vhost.ossrs.net
 | ||||
| * @param schema, for example, rtmp | ||||
| * @param host, for example, 192.168.1.10 | ||||
| * @param vhost, for example, vhost.ossrs.net. | ||||
| *       vhost default to host, when user not set vhost in query of app. | ||||
| * @param app, for example, live | ||||
| * @param port, for example, 19350 | ||||
| *       default to 1935 if not specified. | ||||
| * param param, for example, vhost=vhost.ossrs.net | ||||
| */ | ||||
| extern void srs_discovery_tc_url( | ||||
|     std::string tcUrl,  | ||||
|     std::string& schema, std::string& host, std::string& vhost,  | ||||
|     std::string& app, std::string& port, std::string& param | ||||
| ); | ||||
| 
 | ||||
| /**
 | ||||
| * resolve the vhost in query string | ||||
| * @pram vhost, update the vhost if query contains the vhost. | ||||
| * @param app, may contains the vhost in query string format: | ||||
| *   app?vhost=request_vhost | ||||
| *   app...vhost...request_vhost | ||||
| * @param param, the query, for example, ?vhost=xxx | ||||
| */  | ||||
| extern void srs_vhost_resolve(std::string& vhost, std::string& app, std::string& param); | ||||
| 
 | ||||
| /**
 | ||||
| * generate ramdom data for handshake. | ||||
| */ | ||||
| extern void srs_random_generate(char* bytes, int size); | ||||
| 
 | ||||
| /**
 | ||||
| * generate the tcUrl. | ||||
| * @param param, the app parameters in tcUrl. for example, ?key=xxx,vhost=xxx | ||||
| * @return the tcUrl generated from ip/vhost/app/port. | ||||
| * @remark when vhost equals to __defaultVhost__, use ip as vhost. | ||||
| * @remark ignore port if port equals to default port 1935. | ||||
| */ | ||||
| extern std::string srs_generate_tc_url( | ||||
|     std::string ip, std::string vhost, std::string app, std::string port, | ||||
|     std::string param | ||||
| ); | ||||
| 
 | ||||
| /**
 | ||||
| * compare the memory in bytes. | ||||
| * @return true if completely equal; otherwise, false. | ||||
| */ | ||||
| extern bool srs_bytes_equals(void* pa, void* pb, int size); | ||||
| 
 | ||||
| /**
 | ||||
| * generate the c0 chunk header for msg. | ||||
| * @param cache, the cache to write header. | ||||
| * @param nb_cache, the size of cache. | ||||
| * @return the size of header. 0 if cache not enough. | ||||
| */ | ||||
| extern int srs_chunk_header_c0( | ||||
|     int perfer_cid, u_int32_t timestamp, int32_t payload_length, | ||||
|     int8_t message_type, int32_t stream_id, | ||||
|     char* cache, int nb_cache | ||||
| ); | ||||
| 
 | ||||
| /**
 | ||||
| * generate the c3 chunk header for msg. | ||||
| * @param cache, the cache to write header. | ||||
| * @param nb_cache, the size of cache. | ||||
| * @return the size of header. 0 if cache not enough. | ||||
| */ | ||||
| extern int srs_chunk_header_c3( | ||||
|     int perfer_cid, u_int32_t timestamp,  | ||||
|     char* cache, int nb_cache | ||||
| ); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue