winlin

change to 0.9.42, add http parse framework

@@ -204,8 +204,9 @@ help: @@ -204,8 +204,9 @@ help:
204 @echo " uninstall uninstall srs from prefix path" 204 @echo " uninstall uninstall srs from prefix path"
205 205
206 clean: 206 clean:
207 - (cd ${SRS_OBJS}; rm -f rm -rf srs bandwidth srs_utest)  
208 - (cd ${SRS_OBJS}; rm -rf src research include lib utest) 207 + (cd ${SRS_OBJS}; rm -rf srs bandwidth srs_utest)
  208 + (cd ${SRS_OBJS}; rm -rf src research include lib)
  209 + (cd ${SRS_OBJS}/utest; rm -rf *.o *.a)
209 (cd research/librtmp; make clean) 210 (cd research/librtmp; make clean)
210 (cd research/api-server/static-dir; rm -rf crossdomain.xml forward live players) 211 (cd research/api-server/static-dir; rm -rf crossdomain.xml forward live players)
211 212
@@ -43,6 +43,9 @@ using namespace srs; @@ -43,6 +43,9 @@ using namespace srs;
43 #define SRS_DEFAULT_HTTP_PORT 80 43 #define SRS_DEFAULT_HTTP_PORT 80
44 #define SRS_HTTP_RESPONSE_OK "0" 44 #define SRS_HTTP_RESPONSE_OK "0"
45 45
  46 +#define SRS_HTTP_HEADER_BUFFER 1024
  47 +#define SRS_HTTP_BODY_BUFFER 32 * 1024
  48 +
46 SrsHttpUri::SrsHttpUri() 49 SrsHttpUri::SrsHttpUri()
47 { 50 {
48 port = SRS_DEFAULT_HTTP_PORT; 51 port = SRS_DEFAULT_HTTP_PORT;
@@ -153,13 +156,13 @@ int SrsHttpClient::post(SrsHttpUri* uri, std::string req, std::string& res) @@ -153,13 +156,13 @@ int SrsHttpClient::post(SrsHttpUri* uri, std::string req, std::string& res)
153 // POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s 156 // POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s
154 std::stringstream ss; 157 std::stringstream ss;
155 ss << "POST " << uri->get_path() << " " 158 ss << "POST " << uri->get_path() << " "
156 - << "HTTP/1.1" << CRLF  
157 - << "Host: " << uri->get_host() << CRLF  
158 - << "Connection: Keep-Alive" << CRLF  
159 - << "Content-Length: " << std::dec << req.length() << CRLF  
160 - << "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << CRLF  
161 - << "Content-Type: text/html" << CRLF  
162 - << CRLF 159 + << "HTTP/1.1" << __CRLF
  160 + << "Host: " << uri->get_host() << __CRLF
  161 + << "Connection: Keep-Alive" << __CRLF
  162 + << "Content-Length: " << std::dec << req.length() << __CRLF
  163 + << "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __CRLF
  164 + << "Content-Type: text/html" << __CRLF
  165 + << __CRLF
163 << req; 166 << req;
164 167
165 SrsSocket skt(stfd); 168 SrsSocket skt(stfd);
@@ -375,13 +378,13 @@ int SrsHttpClient::parse_response_body_data(SrsHttpUri* uri, SrsSocket* skt, std @@ -375,13 +378,13 @@ int SrsHttpClient::parse_response_body_data(SrsHttpUri* uri, SrsSocket* skt, std
375 int SrsHttpClient::on_headers_complete(http_parser* parser) 378 int SrsHttpClient::on_headers_complete(http_parser* parser)
376 { 379 {
377 SrsHttpClient* obj = (SrsHttpClient*)parser->data; 380 SrsHttpClient* obj = (SrsHttpClient*)parser->data;
378 - obj->comple_header(parser); 381 + obj->complete_header(parser);
379 382
380 // see http_parser.c:1570, return 1 to skip body. 383 // see http_parser.c:1570, return 1 to skip body.
381 return 1; 384 return 1;
382 } 385 }
383 386
384 -void SrsHttpClient::comple_header(http_parser* parser) 387 +void SrsHttpClient::complete_header(http_parser* parser)
385 { 388 {
386 // save the parser status when header parse completed. 389 // save the parser status when header parse completed.
387 memcpy(&http_header, parser, sizeof(http_header)); 390 memcpy(&http_header, parser, sizeof(http_header));
@@ -35,18 +35,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -35,18 +35,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 namespace srs 35 namespace srs
36 { 36 {
37 // CR = <US-ASCII CR, carriage return (13)> 37 // CR = <US-ASCII CR, carriage return (13)>
38 - const static char CR = '\r'; 38 + #define __CR "\r" // 0x0D
39 // LF = <US-ASCII LF, linefeed (10)> 39 // LF = <US-ASCII LF, linefeed (10)>
40 - const static char LF = '\n'; 40 + #define __LF "\n" // 0x0A
41 // SP = <US-ASCII SP, space (32)> 41 // SP = <US-ASCII SP, space (32)>
42 - const static char SP = ' '; 42 + #define __SP " " // 0x20
43 // HT = <US-ASCII HT, horizontal-tab (9)> 43 // HT = <US-ASCII HT, horizontal-tab (9)>
44 - const static char HT = 9; 44 + #define __HT "\x09" // 0x09
45 45
46 // HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all 46 // HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
47 // protocol elements except the entity-body (see appendix 19.3 for 47 // protocol elements except the entity-body (see appendix 19.3 for
48 // tolerant applications). 48 // tolerant applications).
49 - const static char* CRLF = "\r\n"; 49 + #define __CRLF __CR""__LF // 0x0D0A
50 }; 50 };
51 51
52 #ifdef SRS_HTTP_CALLBACK 52 #ifdef SRS_HTTP_CALLBACK
@@ -58,9 +58,6 @@ class SrsSocket; @@ -58,9 +58,6 @@ class SrsSocket;
58 58
59 #include <http_parser.h> 59 #include <http_parser.h>
60 60
61 -#define SRS_HTTP_HEADER_BUFFER 1024  
62 -#define SRS_HTTP_BODY_BUFFER 32 * 1024  
63 -  
64 /** 61 /**
65 * used to resolve the http uri. 62 * used to resolve the http uri.
66 */ 63 */
@@ -124,7 +121,7 @@ private: @@ -124,7 +121,7 @@ private:
124 virtual int parse_response_body_data(SrsHttpUri* uri, SrsSocket* skt, std::string* response, size_t body_left, const void* buf, size_t size); 121 virtual int parse_response_body_data(SrsHttpUri* uri, SrsSocket* skt, std::string* response, size_t body_left, const void* buf, size_t size);
125 private: 122 private:
126 static int on_headers_complete(http_parser* parser); 123 static int on_headers_complete(http_parser* parser);
127 - virtual void comple_header(http_parser* parser); 124 + virtual void complete_header(http_parser* parser);
128 }; 125 };
129 126
130 /** 127 /**
@@ -25,6 +25,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -25,6 +25,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 25
26 #include <srs_kernel_log.hpp> 26 #include <srs_kernel_log.hpp>
27 #include <srs_kernel_error.hpp> 27 #include <srs_kernel_error.hpp>
  28 +#include <srs_app_socket.hpp>
  29 +
  30 +#define SRS_HTTP_HEADER_BUFFER 1024
28 31
29 SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd) 32 SrsHttpConn::SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd)
30 : SrsConnection(srs_server, client_stfd) 33 : SrsConnection(srs_server, client_stfd)
@@ -45,12 +48,150 @@ int SrsHttpConn::do_cycle() @@ -45,12 +48,150 @@ int SrsHttpConn::do_cycle()
45 } 48 }
46 srs_trace("http get peer ip success. ip=%s", ip); 49 srs_trace("http get peer ip success. ip=%s", ip);
47 50
  51 + // setup http parser
  52 + http_parser_settings settings;
  53 +
  54 + memset(&settings, 0, sizeof(settings));
  55 + settings.on_message_begin = on_message_begin;
  56 + settings.on_url = on_url;
  57 + settings.on_header_field = on_header_field;
  58 + settings.on_header_value = on_header_value;
  59 + settings.on_headers_complete = on_headers_complete;
  60 + settings.on_body = on_body;
  61 + settings.on_message_complete = on_message_complete;
  62 +
  63 + http_parser parser;
  64 + http_parser_init(&parser, HTTP_REQUEST);
  65 + // callback object ptr.
  66 + parser.data = (void*)this;
  67 +
  68 + // underlayer socket
  69 + SrsSocket skt(stfd);
  70 +
  71 + for (;;) {
  72 + if ((ret = process_request(&skt, &parser, &settings)) != ERROR_SUCCESS) {
  73 + if (!srs_is_client_gracefully_close(ret)) {
  74 + srs_error("http client cycle failed. ret=%d", ret);
  75 + }
  76 + return ret;
  77 + }
  78 + }
  79 +
  80 + return ret;
  81 +}
  82 +
  83 +int SrsHttpConn::process_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings)
  84 +{
  85 + int ret = ERROR_SUCCESS;
  86 +
  87 + // reset response header.
  88 + http_header = NULL;
  89 +
  90 + // parser header.
  91 + char buf[SRS_HTTP_HEADER_BUFFER];
  92 + for (;;) {
  93 + ssize_t nread;
  94 + if ((ret = skt->read(buf, (size_t)sizeof(buf), &nread)) != ERROR_SUCCESS) {
  95 + if (!srs_is_client_gracefully_close(ret)) {
  96 + srs_error("read body from server failed. ret=%d", ret);
  97 + }
  98 + return ret;
  99 + }
  100 +
  101 + ssize_t nparsed = http_parser_execute(parser, settings, buf, nread);
  102 + srs_info("read_size=%d, nparsed=%d", (int)nread, (int)nparsed);
  103 +
  104 + // check header size.
  105 + if (http_header) {
  106 + int nb_body = nread - nparsed;
  107 +
  108 + srs_info("http header parsed, size=%d, content-length=%"PRId64", nb_body=%d",
  109 + http_header->nread, http_header->content_length, nb_body);
  110 +
  111 + return complete_header(skt, http_header, buf + nparsed, nb_body);
  112 + }
  113 +
  114 + if (nparsed != nread) {
  115 + ret = ERROR_HTTP_PARSE_HEADER;
  116 + srs_error("parse response error, parsed(%d)!=read(%d), ret=%d", (int)nparsed, (int)nread, ret);
  117 + return ret;
  118 + }
  119 + }
  120 +
  121 + return ret;
  122 +}
  123 +
  124 +int SrsHttpConn::complete_header(SrsSocket* skt, http_parser* header, char* body, int nb_body)
  125 +{
  126 + int ret = ERROR_SUCCESS;
  127 +
48 char data[] = "HTTP/1.1 200 OK\r\n" 128 char data[] = "HTTP/1.1 200 OK\r\n"
49 "Server: SRS/"RTMP_SIG_SRS_VERSION"\r\n" 129 "Server: SRS/"RTMP_SIG_SRS_VERSION"\r\n"
50 "Content-Length: 15\r\n" 130 "Content-Length: 15\r\n"
51 "Content-Type: text/html;charset=utf-8\r\n\r\n" 131 "Content-Type: text/html;charset=utf-8\r\n\r\n"
52 "hello http/1.1~"; 132 "hello http/1.1~";
53 - st_write(stfd, data, sizeof(data), -1); 133 +
  134 + skt->write(data, sizeof(data), NULL);
54 135
55 return ret; 136 return ret;
56 } 137 }
  138 +
  139 +int SrsHttpConn::on_message_begin(http_parser* parser)
  140 +{
  141 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  142 + (void)obj;
  143 + srs_trace("***MESSAGE BEGIN***");
  144 + return 0;
  145 +}
  146 +
  147 +int SrsHttpConn::on_headers_complete(http_parser* parser)
  148 +{
  149 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  150 + (void)obj;
  151 + srs_trace("***HEADERS COMPLETE***");
  152 +
  153 + // see http_parser.c:1570, return 1 to skip body.
  154 + return 0;
  155 +}
  156 +
  157 +int SrsHttpConn::on_message_complete(http_parser* parser)
  158 +{
  159 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  160 + srs_trace("***MESSAGE COMPLETE***\n");
  161 +
  162 + // save the parser when header parse completed.
  163 + obj->http_header = parser;
  164 + return 0;
  165 +}
  166 +
  167 +int SrsHttpConn::on_url(http_parser* parser, const char* at, size_t length)
  168 +{
  169 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  170 + (void)obj;
  171 + srs_trace("Method: %d, Url: %.*s", parser->method, (int)length, at);
  172 + return 0;
  173 +}
  174 +
  175 +int SrsHttpConn::on_header_field(http_parser* parser, const char* at, size_t length)
  176 +{
  177 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  178 + (void)obj;
  179 + srs_trace("Header field: %.*s", (int)length, at);
  180 + return 0;
  181 +}
  182 +
  183 +int SrsHttpConn::on_header_value(http_parser* parser, const char* at, size_t length)
  184 +{
  185 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  186 + (void)obj;
  187 + srs_trace("Header value: %.*s", (int)length, at);
  188 + return 0;
  189 +}
  190 +
  191 +int SrsHttpConn::on_body(http_parser* parser, const char* at, size_t length)
  192 +{
  193 + SrsHttpConn* obj = (SrsHttpConn*)parser->data;
  194 + (void)obj;
  195 + srs_trace("Body: %.*s", (int)length, at);
  196 + return 0;
  197 +}
@@ -33,13 +33,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,13 +33,30 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include <srs_app_st.hpp> 33 #include <srs_app_st.hpp>
34 #include <srs_app_conn.hpp> 34 #include <srs_app_conn.hpp>
35 35
  36 +#include <http_parser.h>
  37 +
  38 +class SrsSocket;
  39 +
36 class SrsHttpConn : public SrsConnection 40 class SrsHttpConn : public SrsConnection
37 { 41 {
  42 +private:
  43 + http_parser* http_header;
38 public: 44 public:
39 SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd); 45 SrsHttpConn(SrsServer* srs_server, st_netfd_t client_stfd);
40 virtual ~SrsHttpConn(); 46 virtual ~SrsHttpConn();
41 protected: 47 protected:
42 virtual int do_cycle(); 48 virtual int do_cycle();
  49 +private:
  50 + virtual int process_request(SrsSocket* skt, http_parser* parser, http_parser_settings* settings);
  51 + virtual int complete_header(SrsSocket* skt, http_parser* header, char* body, int nb_body);
  52 +private:
  53 + static int on_message_begin(http_parser* parser);
  54 + static int on_headers_complete(http_parser* parser);
  55 + static int on_message_complete(http_parser* parser);
  56 + static int on_url(http_parser* parser, const char* at, size_t length);
  57 + static int on_header_field(http_parser* parser, const char* at, size_t length);
  58 + static int on_header_value(http_parser* parser, const char* at, size_t length);
  59 + static int on_body(http_parser* parser, const char* at, size_t length);
43 }; 60 };
44 61
45 #endif 62 #endif
@@ -99,23 +99,26 @@ int SrsSocket::read(const void* buf, size_t size, ssize_t* nread) @@ -99,23 +99,26 @@ int SrsSocket::read(const void* buf, size_t size, ssize_t* nread)
99 { 99 {
100 int ret = ERROR_SUCCESS; 100 int ret = ERROR_SUCCESS;
101 101
102 - *nread = st_read(stfd, (void*)buf, size, recv_timeout); 102 + ssize_t nb_read = st_read(stfd, (void*)buf, size, recv_timeout);
  103 + if (nread) {
  104 + *nread = nb_read;
  105 + }
103 106
104 // On success a non-negative integer indicating the number of bytes actually read is returned 107 // On success a non-negative integer indicating the number of bytes actually read is returned
105 // (a value of 0 means the network connection is closed or end of file is reached). 108 // (a value of 0 means the network connection is closed or end of file is reached).
106 - if (*nread <= 0) { 109 + if (nb_read <= 0) {
107 if (errno == ETIME) { 110 if (errno == ETIME) {
108 return ERROR_SOCKET_TIMEOUT; 111 return ERROR_SOCKET_TIMEOUT;
109 } 112 }
110 113
111 - if (*nread == 0) { 114 + if (nb_read == 0) {
112 errno = ECONNRESET; 115 errno = ECONNRESET;
113 } 116 }
114 117
115 return ERROR_SOCKET_READ; 118 return ERROR_SOCKET_READ;
116 } 119 }
117 120
118 - recv_bytes += *nread; 121 + recv_bytes += nb_read;
119 122
120 return ret; 123 return ret;
121 } 124 }
@@ -124,23 +127,26 @@ int SrsSocket::read_fully(const void* buf, size_t size, ssize_t* nread) @@ -124,23 +127,26 @@ int SrsSocket::read_fully(const void* buf, size_t size, ssize_t* nread)
124 { 127 {
125 int ret = ERROR_SUCCESS; 128 int ret = ERROR_SUCCESS;
126 129
127 - *nread = st_read_fully(stfd, (void*)buf, size, recv_timeout); 130 + ssize_t nb_read = st_read_fully(stfd, (void*)buf, size, recv_timeout);
  131 + if (nread) {
  132 + *nread = nb_read;
  133 + }
128 134
129 // On success a non-negative integer indicating the number of bytes actually read is returned 135 // On success a non-negative integer indicating the number of bytes actually read is returned
130 // (a value less than nbyte means the network connection is closed or end of file is reached) 136 // (a value less than nbyte means the network connection is closed or end of file is reached)
131 - if (*nread != (ssize_t)size) { 137 + if (nb_read != (ssize_t)size) {
132 if (errno == ETIME) { 138 if (errno == ETIME) {
133 return ERROR_SOCKET_TIMEOUT; 139 return ERROR_SOCKET_TIMEOUT;
134 } 140 }
135 141
136 - if (*nread >= 0) { 142 + if (nb_read >= 0) {
137 errno = ECONNRESET; 143 errno = ECONNRESET;
138 } 144 }
139 145
140 return ERROR_SOCKET_READ_FULLY; 146 return ERROR_SOCKET_READ_FULLY;
141 } 147 }
142 148
143 - recv_bytes += *nread; 149 + recv_bytes += nb_read;
144 150
145 return ret; 151 return ret;
146 } 152 }
@@ -149,9 +155,12 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite) @@ -149,9 +155,12 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite)
149 { 155 {
150 int ret = ERROR_SUCCESS; 156 int ret = ERROR_SUCCESS;
151 157
152 - *nwrite = st_write(stfd, (void*)buf, size, send_timeout); 158 + ssize_t nb_write = st_write(stfd, (void*)buf, size, send_timeout);
  159 + if (nwrite) {
  160 + *nwrite = nb_write;
  161 + }
153 162
154 - if (*nwrite <= 0) { 163 + if (nb_write <= 0) {
155 if (errno == ETIME) { 164 if (errno == ETIME) {
156 return ERROR_SOCKET_TIMEOUT; 165 return ERROR_SOCKET_TIMEOUT;
157 } 166 }
@@ -159,7 +168,7 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite) @@ -159,7 +168,7 @@ int SrsSocket::write(const void* buf, size_t size, ssize_t* nwrite)
159 return ERROR_SOCKET_WRITE; 168 return ERROR_SOCKET_WRITE;
160 } 169 }
161 170
162 - send_bytes += *nwrite; 171 + send_bytes += nb_write;
163 172
164 return ret; 173 return ret;
165 } 174 }
@@ -168,9 +177,12 @@ int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) @@ -168,9 +177,12 @@ int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
168 { 177 {
169 int ret = ERROR_SUCCESS; 178 int ret = ERROR_SUCCESS;
170 179
171 - *nwrite = st_writev(stfd, iov, iov_size, send_timeout); 180 + ssize_t nb_write = st_writev(stfd, iov, iov_size, send_timeout);
  181 + if (nwrite) {
  182 + *nwrite = nb_write;
  183 + }
172 184
173 - if (*nwrite <= 0) { 185 + if (nb_write <= 0) {
174 if (errno == ETIME) { 186 if (errno == ETIME) {
175 return ERROR_SOCKET_TIMEOUT; 187 return ERROR_SOCKET_TIMEOUT;
176 } 188 }
@@ -178,7 +190,7 @@ int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite) @@ -178,7 +190,7 @@ int SrsSocket::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
178 return ERROR_SOCKET_WRITE; 190 return ERROR_SOCKET_WRITE;
179 } 191 }
180 192
181 - send_bytes += *nwrite; 193 + send_bytes += nb_write;
182 194
183 return ret; 195 return ret;
184 } 196 }
@@ -60,8 +60,14 @@ public: @@ -60,8 +60,14 @@ public:
60 virtual int get_recv_kbps(); 60 virtual int get_recv_kbps();
61 virtual int get_send_kbps(); 61 virtual int get_send_kbps();
62 public: 62 public:
  63 + /**
  64 + * @param nread, the actual read bytes, ignore if NULL.
  65 + */
63 virtual int read(const void* buf, size_t size, ssize_t* nread); 66 virtual int read(const void* buf, size_t size, ssize_t* nread);
64 virtual int read_fully(const void* buf, size_t size, ssize_t* nread); 67 virtual int read_fully(const void* buf, size_t size, ssize_t* nread);
  68 + /**
  69 + * @param nwrite, the actual write bytes, ignore if NULL.
  70 + */
65 virtual int write(const void* buf, size_t size, ssize_t* nwrite); 71 virtual int write(const void* buf, size_t size, ssize_t* nwrite);
66 virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite); 72 virtual int writev(const iovec *iov, int iov_size, ssize_t* nwrite);
67 }; 73 };
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR "0" 32 #define VERSION_MAJOR "0"
33 #define VERSION_MINOR "9" 33 #define VERSION_MINOR "9"
34 -#define VERSION_REVISION "41" 34 +#define VERSION_REVISION "42"
35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION 35 #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "srs" 37 #define RTMP_SIG_SRS_KEY "srs"