mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
for #133, support the rtsp options request and response.
This commit is contained in:
parent
c0e50265bd
commit
604f4cc57b
8 changed files with 849 additions and 33 deletions
|
@ -62,7 +62,7 @@ int srs_go_http_response_json(ISrsGoHttpResponseWriter* w, string data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the status text of code.
|
// get the status text of code.
|
||||||
string srs_generate_status_text(int status)
|
string srs_generate_http_status_text(int status)
|
||||||
{
|
{
|
||||||
static std::map<int, std::string> _status_map;
|
static std::map<int, std::string> _status_map;
|
||||||
if (_status_map.empty()) {
|
if (_status_map.empty()) {
|
||||||
|
@ -212,7 +212,7 @@ void SrsGoHttpHeader::write(stringstream& ss)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string>::iterator it;
|
std::map<std::string, std::string>::iterator it;
|
||||||
for (it = headers.begin(); it != headers.end(); ++it) {
|
for (it = headers.begin(); it != headers.end(); ++it) {
|
||||||
ss << it->first << ": " << it->second << __SRS_CRLF;
|
ss << it->first << ": " << it->second << __SRS_HTTP_CRLF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,7 +711,7 @@ int SrsGoHttpResponseWriter::final_request()
|
||||||
// complete the chunked encoding.
|
// complete the chunked encoding.
|
||||||
if (content_length == -1) {
|
if (content_length == -1) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << 0 << __SRS_CRLF << __SRS_CRLF;
|
ss << 0 << __SRS_HTTP_CRLF << __SRS_HTTP_CRLF;
|
||||||
std::string ch = ss.str();
|
std::string ch = ss.str();
|
||||||
return skt->write((void*)ch.data(), (int)ch.length(), NULL);
|
return skt->write((void*)ch.data(), (int)ch.length(), NULL);
|
||||||
}
|
}
|
||||||
|
@ -752,7 +752,7 @@ int SrsGoHttpResponseWriter::write(char* data, int size)
|
||||||
|
|
||||||
// send in chunked encoding.
|
// send in chunked encoding.
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << hex << size << __SRS_CRLF;
|
ss << hex << size << __SRS_HTTP_CRLF;
|
||||||
std::string ch = ss.str();
|
std::string ch = ss.str();
|
||||||
if ((ret = skt->write((void*)ch.data(), (int)ch.length(), NULL)) != ERROR_SUCCESS) {
|
if ((ret = skt->write((void*)ch.data(), (int)ch.length(), NULL)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -760,7 +760,7 @@ int SrsGoHttpResponseWriter::write(char* data, int size)
|
||||||
if ((ret = skt->write((void*)data, size, NULL)) != ERROR_SUCCESS) {
|
if ((ret = skt->write((void*)data, size, NULL)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if ((ret = skt->write((void*)__SRS_CRLF, 2, NULL)) != ERROR_SUCCESS) {
|
if ((ret = skt->write((void*)__SRS_HTTP_CRLF, 2, NULL)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -794,7 +794,7 @@ int SrsGoHttpResponseWriter::send_header(char* data, int size)
|
||||||
|
|
||||||
// status_line
|
// status_line
|
||||||
ss << "HTTP/1.1 " << status << " "
|
ss << "HTTP/1.1 " << status << " "
|
||||||
<< srs_generate_status_text(status) << __SRS_CRLF;
|
<< srs_generate_http_status_text(status) << __SRS_HTTP_CRLF;
|
||||||
|
|
||||||
// detect content type
|
// detect content type
|
||||||
if (srs_go_http_body_allowd(status)) {
|
if (srs_go_http_body_allowd(status)) {
|
||||||
|
@ -820,7 +820,7 @@ int SrsGoHttpResponseWriter::send_header(char* data, int size)
|
||||||
hdr->write(ss);
|
hdr->write(ss);
|
||||||
|
|
||||||
// header_eof
|
// header_eof
|
||||||
ss << __SRS_CRLF;
|
ss << __SRS_HTTP_CRLF;
|
||||||
|
|
||||||
std::string buf = ss.str();
|
std::string buf = ss.str();
|
||||||
return skt->write((void*)buf.c_str(), buf.length(), NULL);
|
return skt->write((void*)buf.c_str(), buf.length(), NULL);
|
||||||
|
|
|
@ -39,6 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <http_parser.h>
|
#include <http_parser.h>
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
|
#include <srs_kernel_consts.hpp>
|
||||||
|
|
||||||
class SrsRequest;
|
class SrsRequest;
|
||||||
class SrsStSocket;
|
class SrsStSocket;
|
||||||
|
@ -51,19 +52,19 @@ class ISrsGoHttpResponseWriter;
|
||||||
|
|
||||||
// http specification
|
// http specification
|
||||||
// CR = <US-ASCII CR, carriage return (13)>
|
// CR = <US-ASCII CR, carriage return (13)>
|
||||||
#define __SRS_CR SRS_CONSTS_CR // 0x0D
|
#define __SRS_HTTP_CR SRS_CONSTS_CR // 0x0D
|
||||||
// LF = <US-ASCII LF, linefeed (10)>
|
// LF = <US-ASCII LF, linefeed (10)>
|
||||||
#define __SRS_LF SRS_CONSTS_LF // 0x0A
|
#define __SRS_HTTP_LF SRS_CONSTS_LF // 0x0A
|
||||||
// SP = <US-ASCII SP, space (32)>
|
// SP = <US-ASCII SP, space (32)>
|
||||||
#define __SRS_SP ' ' // 0x20
|
#define __SRS_HTTP_SP ' ' // 0x20
|
||||||
// HT = <US-ASCII HT, horizontal-tab (9)>
|
// HT = <US-ASCII HT, horizontal-tab (9)>
|
||||||
#define __SRS_HT '\x09' // 0x09
|
#define __SRS_HTTP_HT '\x09' // 0x09
|
||||||
|
|
||||||
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
|
||||||
// protocol elements except the entity-body (see appendix 19.3 for
|
// protocol elements except the entity-body (see appendix 19.3 for
|
||||||
// tolerant applications).
|
// tolerant applications).
|
||||||
#define __SRS_CRLF "\r\n" // 0x0D0A
|
#define __SRS_HTTP_CRLF "\r\n" // 0x0D0A
|
||||||
#define __SRS_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
#define __SRS_HTTP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||||
|
|
||||||
// @see SrsHttpMessage._http_ts_send_buffer
|
// @see SrsHttpMessage._http_ts_send_buffer
|
||||||
#define __SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
#define __SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||||
|
|
|
@ -76,13 +76,13 @@ int SrsHttpClient::post(SrsHttpUri* uri, string req, int& status_code, string& r
|
||||||
// POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s
|
// POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "POST " << uri->get_path() << " "
|
ss << "POST " << uri->get_path() << " "
|
||||||
<< "HTTP/1.1" << __SRS_CRLF
|
<< "HTTP/1.1" << __SRS_HTTP_CRLF
|
||||||
<< "Host: " << uri->get_host() << __SRS_CRLF
|
<< "Host: " << uri->get_host() << __SRS_HTTP_CRLF
|
||||||
<< "Connection: Keep-Alive" << __SRS_CRLF
|
<< "Connection: Keep-Alive" << __SRS_HTTP_CRLF
|
||||||
<< "Content-Length: " << std::dec << req.length() << __SRS_CRLF
|
<< "Content-Length: " << std::dec << req.length() << __SRS_HTTP_CRLF
|
||||||
<< "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __SRS_CRLF
|
<< "User-Agent: " << RTMP_SIG_SRS_NAME << RTMP_SIG_SRS_VERSION << __SRS_HTTP_CRLF
|
||||||
<< "Content-Type: application/json" << __SRS_CRLF
|
<< "Content-Type: application/json" << __SRS_HTTP_CRLF
|
||||||
<< __SRS_CRLF
|
<< __SRS_HTTP_CRLF
|
||||||
<< req;
|
<< req;
|
||||||
|
|
||||||
SrsStSocket skt(stfd);
|
SrsStSocket skt(stfd);
|
||||||
|
|
|
@ -32,6 +32,7 @@ using namespace std;
|
||||||
#include <srs_app_st_socket.hpp>
|
#include <srs_app_st_socket.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
#include <srs_app_utility.hpp>
|
#include <srs_app_utility.hpp>
|
||||||
|
#include <srs_core_autofree.hpp>
|
||||||
|
|
||||||
#ifdef SRS_AUTO_STREAM_CASTER
|
#ifdef SRS_AUTO_STREAM_CASTER
|
||||||
|
|
||||||
|
@ -76,6 +77,28 @@ int SrsRtspConn::do_cycle()
|
||||||
std::string ip = srs_get_peer_ip(st_netfd_fileno(stfd));
|
std::string ip = srs_get_peer_ip(st_netfd_fileno(stfd));
|
||||||
srs_trace("rtsp: serve %s", ip.c_str());
|
srs_trace("rtsp: serve %s", ip.c_str());
|
||||||
|
|
||||||
|
// consume all rtsp messages.
|
||||||
|
for (;;) {
|
||||||
|
SrsRtspRequest* req = NULL;
|
||||||
|
if ((ret = rtsp->recv_message(&req)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: recv request failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
SrsAutoFree(SrsRtspRequest, req);
|
||||||
|
srs_info("rtsp: got rtsp request");
|
||||||
|
|
||||||
|
if (req->is_options()) {
|
||||||
|
if ((ret = rtsp->send_message(new SrsRtspOptionsResponse(req->seq))) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: send response failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -265,43 +265,137 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#define SRS_CONSTS_HTTP_Continue_str "Continue"
|
#define SRS_CONSTS_HTTP_Continue_str "Continue"
|
||||||
#define SRS_CONSTS_HTTP_SwitchingProtocols_str "Switching Protocols"
|
#define SRS_CONSTS_HTTP_SwitchingProtocols_str "Switching Protocols"
|
||||||
#define SRS_CONSTS_HTTP_OK_str "OK"
|
#define SRS_CONSTS_HTTP_OK_str "OK"
|
||||||
#define SRS_CONSTS_HTTP_Created_str "Created "
|
#define SRS_CONSTS_HTTP_Created_str "Created"
|
||||||
#define SRS_CONSTS_HTTP_Accepted_str "Accepted"
|
#define SRS_CONSTS_HTTP_Accepted_str "Accepted"
|
||||||
#define SRS_CONSTS_HTTP_NonAuthoritativeInformation_str "Non Authoritative Information "
|
#define SRS_CONSTS_HTTP_NonAuthoritativeInformation_str "Non Authoritative Information"
|
||||||
#define SRS_CONSTS_HTTP_NoContent_str "No Content "
|
#define SRS_CONSTS_HTTP_NoContent_str "No Content"
|
||||||
#define SRS_CONSTS_HTTP_ResetContent_str "Reset Content"
|
#define SRS_CONSTS_HTTP_ResetContent_str "Reset Content"
|
||||||
#define SRS_CONSTS_HTTP_PartialContent_str "Partial Content"
|
#define SRS_CONSTS_HTTP_PartialContent_str "Partial Content"
|
||||||
#define SRS_CONSTS_HTTP_MultipleChoices_str "Multiple Choices "
|
#define SRS_CONSTS_HTTP_MultipleChoices_str "Multiple Choices"
|
||||||
#define SRS_CONSTS_HTTP_MovedPermanently_str "Moved Permanently"
|
#define SRS_CONSTS_HTTP_MovedPermanently_str "Moved Permanently"
|
||||||
#define SRS_CONSTS_HTTP_Found_str "Found"
|
#define SRS_CONSTS_HTTP_Found_str "Found"
|
||||||
#define SRS_CONSTS_HTTP_SeeOther_str "See Other"
|
#define SRS_CONSTS_HTTP_SeeOther_str "See Other"
|
||||||
#define SRS_CONSTS_HTTP_NotModified_str "Not Modified "
|
#define SRS_CONSTS_HTTP_NotModified_str "Not Modified"
|
||||||
#define SRS_CONSTS_HTTP_UseProxy_str "Use Proxy"
|
#define SRS_CONSTS_HTTP_UseProxy_str "Use Proxy"
|
||||||
#define SRS_CONSTS_HTTP_TemporaryRedirect_str "Temporary Redirect "
|
#define SRS_CONSTS_HTTP_TemporaryRedirect_str "Temporary Redirect"
|
||||||
#define SRS_CONSTS_HTTP_BadRequest_str "Bad Request"
|
#define SRS_CONSTS_HTTP_BadRequest_str "Bad Request"
|
||||||
#define SRS_CONSTS_HTTP_Unauthorized_str "Unauthorized"
|
#define SRS_CONSTS_HTTP_Unauthorized_str "Unauthorized"
|
||||||
#define SRS_CONSTS_HTTP_PaymentRequired_str "Payment Required "
|
#define SRS_CONSTS_HTTP_PaymentRequired_str "Payment Required"
|
||||||
#define SRS_CONSTS_HTTP_Forbidden_str "Forbidden "
|
#define SRS_CONSTS_HTTP_Forbidden_str "Forbidden"
|
||||||
#define SRS_CONSTS_HTTP_NotFound_str "Not Found"
|
#define SRS_CONSTS_HTTP_NotFound_str "Not Found"
|
||||||
#define SRS_CONSTS_HTTP_MethodNotAllowed_str "Method Not Allowed"
|
#define SRS_CONSTS_HTTP_MethodNotAllowed_str "Method Not Allowed"
|
||||||
#define SRS_CONSTS_HTTP_NotAcceptable_str "Not Acceptable "
|
#define SRS_CONSTS_HTTP_NotAcceptable_str "Not Acceptable"
|
||||||
#define SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str "Proxy Authentication Required "
|
#define SRS_CONSTS_HTTP_ProxyAuthenticationRequired_str "Proxy Authentication Required"
|
||||||
#define SRS_CONSTS_HTTP_RequestTimeout_str "Request Timeout"
|
#define SRS_CONSTS_HTTP_RequestTimeout_str "Request Timeout"
|
||||||
#define SRS_CONSTS_HTTP_Conflict_str "Conflict"
|
#define SRS_CONSTS_HTTP_Conflict_str "Conflict"
|
||||||
#define SRS_CONSTS_HTTP_Gone_str "Gone"
|
#define SRS_CONSTS_HTTP_Gone_str "Gone"
|
||||||
#define SRS_CONSTS_HTTP_LengthRequired_str "Length Required"
|
#define SRS_CONSTS_HTTP_LengthRequired_str "Length Required"
|
||||||
#define SRS_CONSTS_HTTP_PreconditionFailed_str "Precondition Failed"
|
#define SRS_CONSTS_HTTP_PreconditionFailed_str "Precondition Failed"
|
||||||
#define SRS_CONSTS_HTTP_RequestEntityTooLarge_str "Request Entity Too Large "
|
#define SRS_CONSTS_HTTP_RequestEntityTooLarge_str "Request Entity Too Large"
|
||||||
#define SRS_CONSTS_HTTP_RequestURITooLarge_str "Request URI Too Large"
|
#define SRS_CONSTS_HTTP_RequestURITooLarge_str "Request URI Too Large"
|
||||||
#define SRS_CONSTS_HTTP_UnsupportedMediaType_str "Unsupported Media Type"
|
#define SRS_CONSTS_HTTP_UnsupportedMediaType_str "Unsupported Media Type"
|
||||||
#define SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str "Requested Range Not Satisfiable"
|
#define SRS_CONSTS_HTTP_RequestedRangeNotSatisfiable_str "Requested Range Not Satisfiable"
|
||||||
#define SRS_CONSTS_HTTP_ExpectationFailed_str "Expectation Failed "
|
#define SRS_CONSTS_HTTP_ExpectationFailed_str "Expectation Failed"
|
||||||
#define SRS_CONSTS_HTTP_InternalServerError_str "Internal Server Error "
|
#define SRS_CONSTS_HTTP_InternalServerError_str "Internal Server Error"
|
||||||
#define SRS_CONSTS_HTTP_NotImplemented_str "Not Implemented"
|
#define SRS_CONSTS_HTTP_NotImplemented_str "Not Implemented"
|
||||||
#define SRS_CONSTS_HTTP_BadGateway_str "Bad Gateway"
|
#define SRS_CONSTS_HTTP_BadGateway_str "Bad Gateway"
|
||||||
#define SRS_CONSTS_HTTP_ServiceUnavailable_str "Service Unavailable"
|
#define SRS_CONSTS_HTTP_ServiceUnavailable_str "Service Unavailable"
|
||||||
#define SRS_CONSTS_HTTP_GatewayTimeout_str "Gateway Timeout"
|
#define SRS_CONSTS_HTTP_GatewayTimeout_str "Gateway Timeout"
|
||||||
#define SRS_CONSTS_HTTP_HTTPVersionNotSupported_str "HTTP Version Not Supported"
|
#define SRS_CONSTS_HTTP_HTTPVersionNotSupported_str "HTTP Version Not Supported"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// RTSP consts values
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// 7.1.1 Status Code and Reason Phrase
|
||||||
|
#define SRS_CONSTS_RTSP_Continue 100
|
||||||
|
#define SRS_CONSTS_RTSP_OK 200
|
||||||
|
#define SRS_CONSTS_RTSP_Created 201
|
||||||
|
#define SRS_CONSTS_RTSP_LowOnStorageSpace 250
|
||||||
|
#define SRS_CONSTS_RTSP_MultipleChoices 300
|
||||||
|
#define SRS_CONSTS_RTSP_MovedPermanently 301
|
||||||
|
#define SRS_CONSTS_RTSP_MovedTemporarily 302
|
||||||
|
#define SRS_CONSTS_RTSP_SeeOther 303
|
||||||
|
#define SRS_CONSTS_RTSP_NotModified 304
|
||||||
|
#define SRS_CONSTS_RTSP_UseProxy 305
|
||||||
|
#define SRS_CONSTS_RTSP_BadRequest 400
|
||||||
|
#define SRS_CONSTS_RTSP_Unauthorized 401
|
||||||
|
#define SRS_CONSTS_RTSP_PaymentRequired 402
|
||||||
|
#define SRS_CONSTS_RTSP_Forbidden 403
|
||||||
|
#define SRS_CONSTS_RTSP_NotFound 404
|
||||||
|
#define SRS_CONSTS_RTSP_MethodNotAllowed 405
|
||||||
|
#define SRS_CONSTS_RTSP_NotAcceptable 406
|
||||||
|
#define SRS_CONSTS_RTSP_ProxyAuthenticationRequired 407
|
||||||
|
#define SRS_CONSTS_RTSP_RequestTimeout 408
|
||||||
|
#define SRS_CONSTS_RTSP_Gone 410
|
||||||
|
#define SRS_CONSTS_RTSP_LengthRequired 411
|
||||||
|
#define SRS_CONSTS_RTSP_PreconditionFailed 412
|
||||||
|
#define SRS_CONSTS_RTSP_RequestEntityTooLarge 413
|
||||||
|
#define SRS_CONSTS_RTSP_RequestURITooLarge 414
|
||||||
|
#define SRS_CONSTS_RTSP_UnsupportedMediaType 415
|
||||||
|
#define SRS_CONSTS_RTSP_ParameterNotUnderstood 451
|
||||||
|
#define SRS_CONSTS_RTSP_ConferenceNotFound 452
|
||||||
|
#define SRS_CONSTS_RTSP_NotEnoughBandwidth 453
|
||||||
|
#define SRS_CONSTS_RTSP_SessionNotFound 454
|
||||||
|
#define SRS_CONSTS_RTSP_MethodNotValidInThisState 455
|
||||||
|
#define SRS_CONSTS_RTSP_HeaderFieldNotValidForResource 456
|
||||||
|
#define SRS_CONSTS_RTSP_InvalidRange 457
|
||||||
|
#define SRS_CONSTS_RTSP_ParameterIsReadOnly 458
|
||||||
|
#define SRS_CONSTS_RTSP_AggregateOperationNotAllowed 459
|
||||||
|
#define SRS_CONSTS_RTSP_OnlyAggregateOperationAllowed 460
|
||||||
|
#define SRS_CONSTS_RTSP_UnsupportedTransport 461
|
||||||
|
#define SRS_CONSTS_RTSP_DestinationUnreachable 462
|
||||||
|
#define SRS_CONSTS_RTSP_InternalServerError 500
|
||||||
|
#define SRS_CONSTS_RTSP_NotImplemented 501
|
||||||
|
#define SRS_CONSTS_RTSP_BadGateway 502
|
||||||
|
#define SRS_CONSTS_RTSP_ServiceUnavailable 503
|
||||||
|
#define SRS_CONSTS_RTSP_GatewayTimeout 504
|
||||||
|
#define SRS_CONSTS_RTSP_RTSPVersionNotSupported 505
|
||||||
|
#define SRS_CONSTS_RTSP_OptionNotSupported 551
|
||||||
|
|
||||||
|
#define SRS_CONSTS_RTSP_Continue_str "Continue"
|
||||||
|
#define SRS_CONSTS_RTSP_OK_str "OK"
|
||||||
|
#define SRS_CONSTS_RTSP_Created_str "Created"
|
||||||
|
#define SRS_CONSTS_RTSP_LowOnStorageSpace_str "Low on Storage Space"
|
||||||
|
#define SRS_CONSTS_RTSP_MultipleChoices_str "Multiple Choices"
|
||||||
|
#define SRS_CONSTS_RTSP_MovedPermanently_str "Moved Permanently"
|
||||||
|
#define SRS_CONSTS_RTSP_MovedTemporarily_str "Moved Temporarily"
|
||||||
|
#define SRS_CONSTS_RTSP_SeeOther_str "See Other"
|
||||||
|
#define SRS_CONSTS_RTSP_NotModified_str "Not Modified"
|
||||||
|
#define SRS_CONSTS_RTSP_UseProxy_str "Use Proxy"
|
||||||
|
#define SRS_CONSTS_RTSP_BadRequest_str "Bad Request"
|
||||||
|
#define SRS_CONSTS_RTSP_Unauthorized_str "Unauthorized"
|
||||||
|
#define SRS_CONSTS_RTSP_PaymentRequired_str "Payment Required"
|
||||||
|
#define SRS_CONSTS_RTSP_Forbidden_str "Forbidden"
|
||||||
|
#define SRS_CONSTS_RTSP_NotFound_str "Not Found"
|
||||||
|
#define SRS_CONSTS_RTSP_MethodNotAllowed_str "Method Not Allowed"
|
||||||
|
#define SRS_CONSTS_RTSP_NotAcceptable_str "Not Acceptable"
|
||||||
|
#define SRS_CONSTS_RTSP_ProxyAuthenticationRequired_str "Proxy Authentication Required"
|
||||||
|
#define SRS_CONSTS_RTSP_RequestTimeout_str "Request Timeout"
|
||||||
|
#define SRS_CONSTS_RTSP_Gone_str "Gone"
|
||||||
|
#define SRS_CONSTS_RTSP_LengthRequired_str "Length Required"
|
||||||
|
#define SRS_CONSTS_RTSP_PreconditionFailed_str "Precondition Failed"
|
||||||
|
#define SRS_CONSTS_RTSP_RequestEntityTooLarge_str "Request Entity Too Large"
|
||||||
|
#define SRS_CONSTS_RTSP_RequestURITooLarge_str "Request URI Too Large"
|
||||||
|
#define SRS_CONSTS_RTSP_UnsupportedMediaType_str "Unsupported Media Type"
|
||||||
|
#define SRS_CONSTS_RTSP_ParameterNotUnderstood_str "Invalid parameter"
|
||||||
|
#define SRS_CONSTS_RTSP_ConferenceNotFound_str "Illegal Conference Identifier"
|
||||||
|
#define SRS_CONSTS_RTSP_NotEnoughBandwidth_str "Not Enough Bandwidth"
|
||||||
|
#define SRS_CONSTS_RTSP_SessionNotFound_str "Session Not Found"
|
||||||
|
#define SRS_CONSTS_RTSP_MethodNotValidInThisState_str "Method Not Valid In This State"
|
||||||
|
#define SRS_CONSTS_RTSP_HeaderFieldNotValidForResource_str "Header Field Not Valid"
|
||||||
|
#define SRS_CONSTS_RTSP_InvalidRange_str "Invalid Range"
|
||||||
|
#define SRS_CONSTS_RTSP_ParameterIsReadOnly_str "Parameter Is Read-Only"
|
||||||
|
#define SRS_CONSTS_RTSP_AggregateOperationNotAllowed_str "Aggregate Operation Not Allowed"
|
||||||
|
#define SRS_CONSTS_RTSP_OnlyAggregateOperationAllowed_str "Only Aggregate Operation Allowed"
|
||||||
|
#define SRS_CONSTS_RTSP_UnsupportedTransport_str "Unsupported Transport"
|
||||||
|
#define SRS_CONSTS_RTSP_DestinationUnreachable_str "Destination Unreachable"
|
||||||
|
#define SRS_CONSTS_RTSP_InternalServerError_str "Internal Server Error"
|
||||||
|
#define SRS_CONSTS_RTSP_NotImplemented_str "Not Implemented"
|
||||||
|
#define SRS_CONSTS_RTSP_BadGateway_str "Bad Gateway"
|
||||||
|
#define SRS_CONSTS_RTSP_ServiceUnavailable_str "Service Unavailable"
|
||||||
|
#define SRS_CONSTS_RTSP_GatewayTimeout_str "Gateway Timeout"
|
||||||
|
#define SRS_CONSTS_RTSP_RTSPVersionNotSupported_str "RTSP Version Not Supported"
|
||||||
|
#define SRS_CONSTS_RTSP_OptionNotSupported_str "Option not support"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#define ERROR_OpenSslComputeSharedKey 2039
|
#define ERROR_OpenSslComputeSharedKey 2039
|
||||||
#define ERROR_RTMP_MIC_CHUNKSIZE_CHANGED 2040
|
#define ERROR_RTMP_MIC_CHUNKSIZE_CHANGED 2040
|
||||||
#define ERROR_RTMP_MIC_CACHE_OVERFLOW 2041
|
#define ERROR_RTMP_MIC_CACHE_OVERFLOW 2041
|
||||||
|
#define ERROR_RTSP_TOKEN_NOT_NORMAL 2042
|
||||||
|
#define ERROR_RTSP_REQUEST_HEADER_EOF 2043
|
||||||
//
|
//
|
||||||
// system control message,
|
// system control message,
|
||||||
// not an error, but special control logic.
|
// not an error, but special control logic.
|
||||||
|
|
|
@ -23,17 +23,465 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include <srs_rtsp_stack.hpp>
|
#include <srs_rtsp_stack.hpp>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <map>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
#include <srs_rtmp_io.hpp>
|
#include <srs_rtmp_io.hpp>
|
||||||
|
#include <srs_kernel_buffer.hpp>
|
||||||
|
#include <srs_kernel_error.hpp>
|
||||||
|
#include <srs_kernel_log.hpp>
|
||||||
|
#include <srs_kernel_consts.hpp>
|
||||||
|
|
||||||
#ifdef SRS_AUTO_STREAM_CASTER
|
#ifdef SRS_AUTO_STREAM_CASTER
|
||||||
|
|
||||||
|
#define __SRS_RTSP_BUFFER 4096
|
||||||
|
|
||||||
|
// get the status text of code.
|
||||||
|
string srs_generate_rtsp_status_text(int status)
|
||||||
|
{
|
||||||
|
static std::map<int, std::string> _status_map;
|
||||||
|
if (_status_map.empty()) {
|
||||||
|
_status_map[SRS_CONSTS_RTSP_Continue ] = SRS_CONSTS_RTSP_Continue_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_OK ] = SRS_CONSTS_RTSP_OK_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_Created ] = SRS_CONSTS_RTSP_Created_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_LowOnStorageSpace ] = SRS_CONSTS_RTSP_LowOnStorageSpace_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_MultipleChoices ] = SRS_CONSTS_RTSP_MultipleChoices_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_MovedPermanently ] = SRS_CONSTS_RTSP_MovedPermanently_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_MovedTemporarily ] = SRS_CONSTS_RTSP_MovedTemporarily_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_SeeOther ] = SRS_CONSTS_RTSP_SeeOther_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_NotModified ] = SRS_CONSTS_RTSP_NotModified_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_UseProxy ] = SRS_CONSTS_RTSP_UseProxy_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_BadRequest ] = SRS_CONSTS_RTSP_BadRequest_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_Unauthorized ] = SRS_CONSTS_RTSP_Unauthorized_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_PaymentRequired ] = SRS_CONSTS_RTSP_PaymentRequired_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_Forbidden ] = SRS_CONSTS_RTSP_Forbidden_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_NotFound ] = SRS_CONSTS_RTSP_NotFound_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_MethodNotAllowed ] = SRS_CONSTS_RTSP_MethodNotAllowed_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_NotAcceptable ] = SRS_CONSTS_RTSP_NotAcceptable_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_ProxyAuthenticationRequired ] = SRS_CONSTS_RTSP_ProxyAuthenticationRequired_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_RequestTimeout ] = SRS_CONSTS_RTSP_RequestTimeout_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_Gone ] = SRS_CONSTS_RTSP_Gone_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_LengthRequired ] = SRS_CONSTS_RTSP_LengthRequired_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_PreconditionFailed ] = SRS_CONSTS_RTSP_PreconditionFailed_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_RequestEntityTooLarge ] = SRS_CONSTS_RTSP_RequestEntityTooLarge_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_RequestURITooLarge ] = SRS_CONSTS_RTSP_RequestURITooLarge_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_UnsupportedMediaType ] = SRS_CONSTS_RTSP_UnsupportedMediaType_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_ParameterNotUnderstood ] = SRS_CONSTS_RTSP_ParameterNotUnderstood_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_ConferenceNotFound ] = SRS_CONSTS_RTSP_ConferenceNotFound_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_NotEnoughBandwidth ] = SRS_CONSTS_RTSP_NotEnoughBandwidth_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_SessionNotFound ] = SRS_CONSTS_RTSP_SessionNotFound_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_MethodNotValidInThisState ] = SRS_CONSTS_RTSP_MethodNotValidInThisState_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_HeaderFieldNotValidForResource ] = SRS_CONSTS_RTSP_HeaderFieldNotValidForResource_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_InvalidRange ] = SRS_CONSTS_RTSP_InvalidRange_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_ParameterIsReadOnly ] = SRS_CONSTS_RTSP_ParameterIsReadOnly_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_AggregateOperationNotAllowed ] = SRS_CONSTS_RTSP_AggregateOperationNotAllowed_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_OnlyAggregateOperationAllowed ] = SRS_CONSTS_RTSP_OnlyAggregateOperationAllowed_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_UnsupportedTransport ] = SRS_CONSTS_RTSP_UnsupportedTransport_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_DestinationUnreachable ] = SRS_CONSTS_RTSP_DestinationUnreachable_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_InternalServerError ] = SRS_CONSTS_RTSP_InternalServerError_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_NotImplemented ] = SRS_CONSTS_RTSP_NotImplemented_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_BadGateway ] = SRS_CONSTS_RTSP_BadGateway_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_ServiceUnavailable ] = SRS_CONSTS_RTSP_ServiceUnavailable_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_GatewayTimeout ] = SRS_CONSTS_RTSP_GatewayTimeout_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_RTSPVersionNotSupported ] = SRS_CONSTS_RTSP_RTSPVersionNotSupported_str ;
|
||||||
|
_status_map[SRS_CONSTS_RTSP_OptionNotSupported ] = SRS_CONSTS_RTSP_OptionNotSupported_str ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string status_text;
|
||||||
|
if (_status_map.find(status) == _status_map.end()) {
|
||||||
|
status_text = "Status Unknown";
|
||||||
|
} else {
|
||||||
|
status_text = _status_map[status];
|
||||||
|
}
|
||||||
|
|
||||||
|
return status_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string srs_generate_rtsp_method_str(SrsRtspMethod method)
|
||||||
|
{
|
||||||
|
switch (method) {
|
||||||
|
case SrsRtspMethodDescribe: return __SRS_METHOD_DESCRIBE;
|
||||||
|
case SrsRtspMethodAnnounce: return __SRS_METHOD_ANNOUNCE;
|
||||||
|
case SrsRtspMethodGetParameter: return __SRS_METHOD_GET_PARAMETER;
|
||||||
|
case SrsRtspMethodOptions: return __SRS_METHOD_OPTIONS;
|
||||||
|
case SrsRtspMethodPause: return __SRS_METHOD_PAUSE;
|
||||||
|
case SrsRtspMethodPlay: return __SRS_METHOD_PLAY;
|
||||||
|
case SrsRtspMethodRecord: return __SRS_METHOD_RECORD;
|
||||||
|
case SrsRtspMethodRedirect: return __SRS_METHOD_REDIRECT;
|
||||||
|
case SrsRtspMethodSetup: return __SRS_METHOD_SETUP;
|
||||||
|
case SrsRtspMethodSetParameter: return __SRS_METHOD_SET_PARAMETER;
|
||||||
|
case SrsRtspMethodTeardown: return __SRS_METHOD_TEARDOWN;
|
||||||
|
default: return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtspRequest::SrsRtspRequest()
|
||||||
|
{
|
||||||
|
seq = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtspRequest::~SrsRtspRequest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SrsRtspRequest::is_options()
|
||||||
|
{
|
||||||
|
return method == __SRS_METHOD_OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtspResponse::SrsRtspResponse(int cseq)
|
||||||
|
{
|
||||||
|
seq = cseq;
|
||||||
|
status = SRS_CONSTS_RTSP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtspResponse::~SrsRtspResponse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
stringstream& SrsRtspResponse::encode(stringstream& ss)
|
||||||
|
{
|
||||||
|
// status line
|
||||||
|
ss << __SRS_VERSION << __SRS_RTSP_SP
|
||||||
|
<< status << __SRS_RTSP_SP
|
||||||
|
<< srs_generate_rtsp_status_text(status) << __SRS_RTSP_CRLF;
|
||||||
|
|
||||||
|
// cseq
|
||||||
|
ss << __SRS_TOKEN_CSEQ << ":" << __SRS_RTSP_SP << seq << __SRS_RTSP_CRLF;
|
||||||
|
|
||||||
|
// others.
|
||||||
|
ss << "Cache-Control: no-store" << __SRS_RTSP_CRLF
|
||||||
|
<< "Pragma: no-cache" << __SRS_RTSP_CRLF
|
||||||
|
<< "Server: " << RTMP_SIG_SRS_SERVER << __SRS_RTSP_CRLF;
|
||||||
|
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtspOptionsResponse::SrsRtspOptionsResponse(int cseq) : SrsRtspResponse(cseq)
|
||||||
|
{
|
||||||
|
methods = (SrsRtspMethod)(SrsRtspMethodDescribe | SrsRtspMethodOptions
|
||||||
|
| SrsRtspMethodPause | SrsRtspMethodPlay | SrsRtspMethodSetup | SrsRtspMethodTeardown
|
||||||
|
| SrsRtspMethodAnnounce | SrsRtspMethodRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsRtspOptionsResponse::~SrsRtspOptionsResponse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
stringstream& SrsRtspOptionsResponse::encode(stringstream& ss)
|
||||||
|
{
|
||||||
|
SrsRtspResponse::encode(ss);
|
||||||
|
|
||||||
|
SrsRtspMethod __methods[] = {
|
||||||
|
SrsRtspMethodDescribe,
|
||||||
|
SrsRtspMethodAnnounce,
|
||||||
|
SrsRtspMethodGetParameter,
|
||||||
|
SrsRtspMethodOptions,
|
||||||
|
SrsRtspMethodPause,
|
||||||
|
SrsRtspMethodPlay,
|
||||||
|
SrsRtspMethodRecord,
|
||||||
|
SrsRtspMethodRedirect,
|
||||||
|
SrsRtspMethodSetup,
|
||||||
|
SrsRtspMethodSetParameter,
|
||||||
|
SrsRtspMethodTeardown,
|
||||||
|
};
|
||||||
|
|
||||||
|
ss << __SRS_TOKEN_PUBLIC << ":" << __SRS_RTSP_SP;
|
||||||
|
|
||||||
|
bool appended = false;
|
||||||
|
int nb_methods = (int)(sizeof(__methods) / sizeof(SrsRtspMethod));
|
||||||
|
for (int i = 0; i < nb_methods; i++) {
|
||||||
|
SrsRtspMethod method = __methods[i];
|
||||||
|
if (((int)methods & (int)method) != (int)method) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appended) {
|
||||||
|
ss << ", ";
|
||||||
|
}
|
||||||
|
ss << srs_generate_rtsp_method_str(method);
|
||||||
|
appended = true;
|
||||||
|
}
|
||||||
|
ss << __SRS_RTSP_CRLF;
|
||||||
|
|
||||||
|
// eof header.
|
||||||
|
ss << __SRS_RTSP_CRLF;
|
||||||
|
|
||||||
|
return ss;
|
||||||
|
}
|
||||||
|
|
||||||
SrsRtspStack::SrsRtspStack(ISrsProtocolReaderWriter* s)
|
SrsRtspStack::SrsRtspStack(ISrsProtocolReaderWriter* s)
|
||||||
{
|
{
|
||||||
|
buf = new SrsSimpleBuffer();
|
||||||
skt = s;
|
skt = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtspStack::~SrsRtspStack()
|
SrsRtspStack::~SrsRtspStack()
|
||||||
{
|
{
|
||||||
|
srs_freep(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::recv_message(SrsRtspRequest** preq)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsRtspRequest* req = new SrsRtspRequest();
|
||||||
|
if ((ret = do_recv_message(req)) != ERROR_SUCCESS) {
|
||||||
|
srs_freep(req);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*preq = req;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::send_message(SrsRtspResponse* res)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
// encode the message to string.
|
||||||
|
res->encode(ss);
|
||||||
|
|
||||||
|
std::string str = ss.str();
|
||||||
|
srs_assert(!str.empty());
|
||||||
|
|
||||||
|
if ((ret = skt->write((char*)str.c_str(), (int)str.length(), NULL)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: send response failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_info("rtsp: send response ok");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::do_recv_message(SrsRtspRequest* req)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// parse request line.
|
||||||
|
if ((ret = recv_token_normal(req->method)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse method failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = recv_token_normal(req->uri)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse uri failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret = recv_token_eof(req->version)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse version failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse headers.
|
||||||
|
for (;;) {
|
||||||
|
// parse the header name
|
||||||
|
std::string token;
|
||||||
|
if ((ret = recv_token_normal(token)) != ERROR_SUCCESS) {
|
||||||
|
if (ret == ERROR_RTSP_REQUEST_HEADER_EOF) {
|
||||||
|
ret = ERROR_SUCCESS;
|
||||||
|
srs_info("rtsp: message header parsed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse token failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the header value according by header name
|
||||||
|
if (token == __SRS_TOKEN_CSEQ) {
|
||||||
|
std::string seq;
|
||||||
|
if ((ret = recv_token_eof(seq)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse seq failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
req->seq = ::atoi(seq.c_str());
|
||||||
|
} else {
|
||||||
|
// unknown header name, parse util EOF.
|
||||||
|
SrsRtspTokenState state = SrsRtspTokenStateNormal;
|
||||||
|
while (state == SrsRtspTokenStateNormal) {
|
||||||
|
std::string value;
|
||||||
|
if ((ret = recv_token(value, state)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse token failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_trace("rtsp: ignore header %s=%s", token.c_str(), value.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse body.
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::recv_token_normal(std::string& token)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsRtspTokenState state;
|
||||||
|
|
||||||
|
if ((ret = recv_token(token, state)) != ERROR_SUCCESS) {
|
||||||
|
if (ret == ERROR_RTSP_REQUEST_HEADER_EOF) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse token failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state != SrsRtspTokenStateNormal) {
|
||||||
|
ret = ERROR_RTSP_TOKEN_NOT_NORMAL;
|
||||||
|
srs_error("rtsp: parse normal token failed, state=%d. ret=%d", state, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::recv_token_eof(std::string& token)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsRtspTokenState state;
|
||||||
|
|
||||||
|
if ((ret = recv_token(token, state)) != ERROR_SUCCESS) {
|
||||||
|
if (ret == ERROR_RTSP_REQUEST_HEADER_EOF) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse token failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state != SrsRtspTokenStateEOF) {
|
||||||
|
ret = ERROR_RTSP_TOKEN_NOT_NORMAL;
|
||||||
|
srs_error("rtsp: parse eof token failed, state=%d. ret=%d", state, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::recv_token_util_eof(std::string& token)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
SrsRtspTokenState state;
|
||||||
|
|
||||||
|
// use 0x00 as ignore the normal token flag.
|
||||||
|
if ((ret = recv_token(token, state, 0x00)) != ERROR_SUCCESS) {
|
||||||
|
if (ret == ERROR_RTSP_REQUEST_HEADER_EOF) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: parse token failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state != SrsRtspTokenStateEOF) {
|
||||||
|
ret = ERROR_RTSP_TOKEN_NOT_NORMAL;
|
||||||
|
srs_error("rtsp: parse eof token failed, state=%d. ret=%d", state, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsRtspStack::recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
// whatever, default to error state.
|
||||||
|
state = SrsRtspTokenStateError;
|
||||||
|
|
||||||
|
// when buffer is empty, append bytes first.
|
||||||
|
bool append_bytes = buf->length() == 0;
|
||||||
|
|
||||||
|
// parse util token.
|
||||||
|
for (;;) {
|
||||||
|
// append bytes if required.
|
||||||
|
if (append_bytes) {
|
||||||
|
append_bytes = false;
|
||||||
|
|
||||||
|
char buffer[__SRS_RTSP_BUFFER];
|
||||||
|
ssize_t nb_read = 0;
|
||||||
|
if ((ret = skt->read(buffer, __SRS_RTSP_BUFFER, &nb_read)) != ERROR_SUCCESS) {
|
||||||
|
if (!srs_is_client_gracefully_close(ret)) {
|
||||||
|
srs_error("rtsp: io read failed. ret=%d", ret);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_info("rtsp: io read %d bytes", nb_read);
|
||||||
|
|
||||||
|
buf->append(buffer, nb_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse one by one.
|
||||||
|
char* start = buf->bytes();
|
||||||
|
char* end = start + buf->length();
|
||||||
|
char* p = start;
|
||||||
|
|
||||||
|
// find util SP/CR/LF, max 2 EOF, to finger out the EOF of message.
|
||||||
|
for (; p < end && p[0] != normal_ch && p[0] != __SRS_RTSP_CR && p[0] != __SRS_RTSP_LF; p++) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// matched.
|
||||||
|
if (p < end) {
|
||||||
|
// finger out the state.
|
||||||
|
if (p[0] == normal_ch) {
|
||||||
|
state = SrsRtspTokenStateNormal;
|
||||||
|
} else {
|
||||||
|
state = SrsRtspTokenStateEOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// got the token.
|
||||||
|
int nb_token = p - start;
|
||||||
|
// trim last ':' character.
|
||||||
|
if (nb_token && p[-1] == ':') {
|
||||||
|
nb_token--;
|
||||||
|
}
|
||||||
|
if (nb_token) {
|
||||||
|
token.append(start, nb_token);
|
||||||
|
} else {
|
||||||
|
ret = ERROR_RTSP_REQUEST_HEADER_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore SP/CR/LF
|
||||||
|
for (int i = 0; i < 2 && p < end && (p[0] == normal_ch || p[0] == __SRS_RTSP_CR || p[0] == __SRS_RTSP_LF); p++, i++) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume the token bytes.
|
||||||
|
srs_assert(p - start);
|
||||||
|
buf->erase(p - start);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append more and parse again.
|
||||||
|
append_bytes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,16 +30,223 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include <srs_core.hpp>
|
#include <srs_core.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <srs_kernel_consts.hpp>
|
||||||
|
|
||||||
#ifdef SRS_AUTO_STREAM_CASTER
|
#ifdef SRS_AUTO_STREAM_CASTER
|
||||||
|
|
||||||
|
class SrsSimpleBuffer;
|
||||||
class ISrsProtocolReaderWriter;
|
class ISrsProtocolReaderWriter;
|
||||||
|
|
||||||
|
// rtsp specification
|
||||||
|
// CR = <US-ASCII CR, carriage return (13)>
|
||||||
|
#define __SRS_RTSP_CR SRS_CONSTS_CR // 0x0D
|
||||||
|
// LF = <US-ASCII LF, linefeed (10)>
|
||||||
|
#define __SRS_RTSP_LF SRS_CONSTS_LF // 0x0A
|
||||||
|
// SP = <US-ASCII SP, space (32)>
|
||||||
|
#define __SRS_RTSP_SP ' ' // 0x20
|
||||||
|
|
||||||
|
// 4 RTSP Message
|
||||||
|
// Lines are terminated by CRLF, but
|
||||||
|
// receivers should be prepared to also interpret CR and LF by
|
||||||
|
// themselves as line terminators.
|
||||||
|
#define __SRS_RTSP_CRLF "\r\n" // 0x0D0A
|
||||||
|
#define __SRS_RTSP_CRLFCRLF "\r\n\r\n" // 0x0D0A0D0A
|
||||||
|
|
||||||
|
// RTSP token
|
||||||
|
#define __SRS_TOKEN_CSEQ "CSeq"
|
||||||
|
#define __SRS_TOKEN_PUBLIC "Public"
|
||||||
|
|
||||||
|
// RTSP methods
|
||||||
|
#define __SRS_METHOD_OPTIONS "OPTIONS"
|
||||||
|
#define __SRS_METHOD_DESCRIBE "DESCRIBE"
|
||||||
|
#define __SRS_METHOD_ANNOUNCE "ANNOUNCE"
|
||||||
|
#define __SRS_METHOD_SETUP "SETUP"
|
||||||
|
#define __SRS_METHOD_PLAY "PLAY"
|
||||||
|
#define __SRS_METHOD_PAUSE "PAUSE"
|
||||||
|
#define __SRS_METHOD_TEARDOWN "TEARDOWN"
|
||||||
|
#define __SRS_METHOD_GET_PARAMETER "GET_PARAMETER"
|
||||||
|
#define __SRS_METHOD_SET_PARAMETER "SET_PARAMETER"
|
||||||
|
#define __SRS_METHOD_REDIRECT "REDIRECT"
|
||||||
|
#define __SRS_METHOD_RECORD "RECORD"
|
||||||
|
// Embedded (Interleaved) Binary Data
|
||||||
|
|
||||||
|
// RTSP-Version
|
||||||
|
#define __SRS_VERSION "RTSP/1.0"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the rtsp request message.
|
||||||
|
* 6 Request
|
||||||
|
* A request message from a client to a server or vice versa includes,
|
||||||
|
* within the first line of that message, the method to be applied to
|
||||||
|
* the resource, the identifier of the resource, and the protocol
|
||||||
|
* version in use.
|
||||||
|
* Request = Request-Line ; Section 6.1
|
||||||
|
* *( general-header ; Section 5
|
||||||
|
* | request-header ; Section 6.2
|
||||||
|
* | entity-header ) ; Section 8.1
|
||||||
|
* CRLF
|
||||||
|
* [ message-body ] ; Section 4.3
|
||||||
|
*/
|
||||||
|
class SrsRtspRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* 6.1 Request Line
|
||||||
|
* Request-Line = Method SP Request-URI SP RTSP-Version CRLF
|
||||||
|
*/
|
||||||
|
std::string method;
|
||||||
|
std::string uri;
|
||||||
|
std::string version;
|
||||||
|
/**
|
||||||
|
* 12.17 CSeq
|
||||||
|
* The CSeq field specifies the sequence number for an RTSP requestresponse
|
||||||
|
* pair. This field MUST be present in all requests and
|
||||||
|
* responses. For every RTSP request containing the given sequence
|
||||||
|
* number, there will be a corresponding response having the same
|
||||||
|
* number. Any retransmitted request must contain the same sequence
|
||||||
|
* number as the original (i.e. the sequence number is not incremented
|
||||||
|
* for retransmissions of the same request).
|
||||||
|
*/
|
||||||
|
int seq;
|
||||||
|
public:
|
||||||
|
SrsRtspRequest();
|
||||||
|
virtual ~SrsRtspRequest();
|
||||||
|
public:
|
||||||
|
virtual bool is_options();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the rtsp response message.
|
||||||
|
* 7 Response
|
||||||
|
* [H6] applies except that HTTP-Version is replaced by RTSP-Version.
|
||||||
|
* Also, RTSP defines additional status codes and does not define some
|
||||||
|
* HTTP codes. The valid response codes and the methods they can be used
|
||||||
|
* with are defined in Table 1.
|
||||||
|
* After receiving and interpreting a request message, the recipient
|
||||||
|
* responds with an RTSP response message.
|
||||||
|
* Response = Status-Line ; Section 7.1
|
||||||
|
* *( general-header ; Section 5
|
||||||
|
* | response-header ; Section 7.1.2
|
||||||
|
* | entity-header ) ; Section 8.1
|
||||||
|
* CRLF
|
||||||
|
* [ message-body ] ; Section 4.3
|
||||||
|
*/
|
||||||
|
class SrsRtspResponse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* 7.1 Status-Line
|
||||||
|
* The first line of a Response message is the Status-Line, consisting
|
||||||
|
* of the protocol version followed by a numeric status code, and the
|
||||||
|
* textual phrase associated with the status code, with each element
|
||||||
|
* separated by SP characters. No CR or LF is allowed except in the
|
||||||
|
* final CRLF sequence.
|
||||||
|
* Status-Line = RTSP-Version SP Status-Code SP Reason-Phrase CRLF
|
||||||
|
*/
|
||||||
|
// @see about the version of rtsp, see __SRS_VERSION
|
||||||
|
// @see about the status of rtsp, see SRS_CONSTS_RTSP_OK
|
||||||
|
int status;
|
||||||
|
/**
|
||||||
|
* 12.17 CSeq
|
||||||
|
* The CSeq field specifies the sequence number for an RTSP requestresponse
|
||||||
|
* pair. This field MUST be present in all requests and
|
||||||
|
* responses. For every RTSP request containing the given sequence
|
||||||
|
* number, there will be a corresponding response having the same
|
||||||
|
* number. Any retransmitted request must contain the same sequence
|
||||||
|
* number as the original (i.e. the sequence number is not incremented
|
||||||
|
* for retransmissions of the same request).
|
||||||
|
*/
|
||||||
|
int seq;
|
||||||
|
public:
|
||||||
|
SrsRtspResponse(int cseq);
|
||||||
|
virtual ~SrsRtspResponse();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* encode message to string.
|
||||||
|
*/
|
||||||
|
virtual std::stringstream& encode(std::stringstream& ss);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 10 Method Definitions
|
||||||
|
* The method token indicates the method to be performed on the resource
|
||||||
|
* identified by the Request-URI. The method is case-sensitive. New
|
||||||
|
* methods may be defined in the future. Method names may not start with
|
||||||
|
* a $ character (decimal 24) and must be a token. Methods are
|
||||||
|
* summarized in Table 2.
|
||||||
|
* Notes on Table 2: PAUSE is recommended, but not required in that a
|
||||||
|
* fully functional server can be built that does not support this
|
||||||
|
* method, for example, for live feeds. If a server does not support a
|
||||||
|
* particular method, it MUST return "501 Not Implemented" and a client
|
||||||
|
* SHOULD not try this method again for this server.
|
||||||
|
*/
|
||||||
|
enum SrsRtspMethod
|
||||||
|
{
|
||||||
|
SrsRtspMethodDescribe = 0x0001,
|
||||||
|
SrsRtspMethodAnnounce = 0x0002,
|
||||||
|
SrsRtspMethodGetParameter = 0x0004,
|
||||||
|
SrsRtspMethodOptions = 0x0008,
|
||||||
|
SrsRtspMethodPause = 0x0010,
|
||||||
|
SrsRtspMethodPlay = 0x0020,
|
||||||
|
SrsRtspMethodRecord = 0x0040,
|
||||||
|
SrsRtspMethodRedirect = 0x0080,
|
||||||
|
SrsRtspMethodSetup = 0x0100,
|
||||||
|
SrsRtspMethodSetParameter = 0x0200,
|
||||||
|
SrsRtspMethodTeardown = 0x0400,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 10.1 OPTIONS
|
||||||
|
* The behavior is equivalent to that described in [H9.2]. An OPTIONS
|
||||||
|
* request may be issued at any time, e.g., if the client is about to
|
||||||
|
* try a nonstandard request. It does not influence server state.
|
||||||
|
*/
|
||||||
|
class SrsRtspOptionsResponse : public SrsRtspResponse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* join of SrsRtspMethod
|
||||||
|
*/
|
||||||
|
SrsRtspMethod methods;
|
||||||
|
public:
|
||||||
|
SrsRtspOptionsResponse(int cseq);
|
||||||
|
virtual ~SrsRtspOptionsResponse();
|
||||||
|
public:
|
||||||
|
virtual std::stringstream& encode(std::stringstream& ss);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the state of rtsp token.
|
||||||
|
*/
|
||||||
|
enum SrsRtspTokenState
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* parse token failed, default state.
|
||||||
|
*/
|
||||||
|
SrsRtspTokenStateError = 100,
|
||||||
|
/**
|
||||||
|
* when SP follow the token.
|
||||||
|
*/
|
||||||
|
SrsRtspTokenStateNormal = 101,
|
||||||
|
/**
|
||||||
|
* when CRLF follow the token.
|
||||||
|
*/
|
||||||
|
SrsRtspTokenStateEOF = 102,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the rtsp protocol stack to parse the rtsp packets.
|
* the rtsp protocol stack to parse the rtsp packets.
|
||||||
*/
|
*/
|
||||||
class SrsRtspStack
|
class SrsRtspStack
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* cached bytes buffer.
|
||||||
|
*/
|
||||||
|
SrsSimpleBuffer* buf;
|
||||||
/**
|
/**
|
||||||
* underlayer socket object, send/recv bytes.
|
* underlayer socket object, send/recv bytes.
|
||||||
*/
|
*/
|
||||||
|
@ -47,6 +254,47 @@ private:
|
||||||
public:
|
public:
|
||||||
SrsRtspStack(ISrsProtocolReaderWriter* s);
|
SrsRtspStack(ISrsProtocolReaderWriter* s);
|
||||||
virtual ~SrsRtspStack();
|
virtual ~SrsRtspStack();
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* recv rtsp message from underlayer io.
|
||||||
|
* @param preq the output rtsp request message, which user must free it.
|
||||||
|
* @return an int error code.
|
||||||
|
* ERROR_RTSP_REQUEST_HEADER_EOF indicates request header EOF.
|
||||||
|
*/
|
||||||
|
virtual int recv_message(SrsRtspRequest** preq);
|
||||||
|
/**
|
||||||
|
* send rtsp message over underlayer io.
|
||||||
|
* @param res the rtsp response message, which user should never free it.
|
||||||
|
* @return an int error code.
|
||||||
|
*/
|
||||||
|
virtual int send_message(SrsRtspResponse* res);
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* recv the rtsp message.
|
||||||
|
*/
|
||||||
|
virtual int do_recv_message(SrsRtspRequest* req);
|
||||||
|
/**
|
||||||
|
* read a normal token from io, error when token state is not normal.
|
||||||
|
*/
|
||||||
|
virtual int recv_token_normal(std::string& token);
|
||||||
|
/**
|
||||||
|
* read a normal token from io, error when token state is not eof.
|
||||||
|
*/
|
||||||
|
virtual int recv_token_eof(std::string& token);
|
||||||
|
/**
|
||||||
|
* read the token util got eof, for example, to read the response status Reason-Phrase
|
||||||
|
*/
|
||||||
|
virtual int recv_token_util_eof(std::string& token);
|
||||||
|
/**
|
||||||
|
* read a token from io, split by SP, endswith CRLF:
|
||||||
|
* token1 SP token2 SP ... tokenN CRLF
|
||||||
|
* @param normal_ch, the char to indicates the normal token.
|
||||||
|
* the SP use to indicates the normal token, @see __SRS_RTSP_SP
|
||||||
|
* the 0x00 use to ignore normal token flag. @see recv_token_util_eof
|
||||||
|
* @param token, output the read token.
|
||||||
|
* @param state, output the token parse state.
|
||||||
|
*/
|
||||||
|
virtual int recv_token(std::string& token, SrsRtspTokenState& state, char normal_ch = __SRS_RTSP_SP);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue