diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 33fa894ef..55af5d06e 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -203,8 +203,8 @@ http_api { # default: off enabled on; # The listen endpoint for HTTPS API. - # default: 1986 - listen 1986; + # default: 1990 + listen 1990; # The SSL private key file, generated by: # openssl genrsa -out server.key 2048 # default: ./conf/server.key @@ -242,6 +242,23 @@ http_server { # for both http static and stream server and apply on all vhosts. # default: on crossdomain on; + # For https_server or HTTPS Streaming. + https { + # Whether enable HTTPS Streaming. + # default: off + enabled on; + # The listen endpoint for HTTPS Streaming. + # default: 8088 + listen 8088; + # The SSL private key file, generated by: + # openssl genrsa -out server.key 2048 + # default: ./conf/server.key + key ./conf/server.key; + # The SSL public cert file, generated by: + # openssl req -new -x509 -key server.key -out server.crt -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=Me/OU=Me/CN=ossrs.net" + # default: ./conf/server.crt + cert ./conf/server.crt; + } } ############################################################################################# diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 14f62018f..af774d152 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -1538,11 +1538,6 @@ srs_error_t SrsConfig::reload_conf(SrsConfig* conf) if ((err = reload_http_api(old_root)) != srs_success) { return srs_error_wrap(err, "http api");; } - - // merge config: http_api.https - if ((err = reload_https_api(old_root)) != srs_success) { - return srs_error_wrap(err, "https api");; - } // merge config: http_stream if ((err = reload_http_stream(old_root)) != srs_success) { @@ -1642,67 +1637,6 @@ srs_error_t SrsConfig::reload_http_api(SrsConfDirective* old_root) return err; } -srs_error_t SrsConfig::reload_https_api(SrsConfDirective* old_root) -{ - srs_error_t err = srs_success; - - // merge config. - std::vector::iterator it; - - // state graph - // old_https_api new_https_api - // DISABLED => ENABLED - // ENABLED => DISABLED - // ENABLED => ENABLED (modified) - - SrsConfDirective* new_http_api = root->get("http_api"); - SrsConfDirective* old_http_api = old_root->get("http_api"); - - SrsConfDirective* new_https_api = (new_http_api? new_http_api->get("https") : NULL); - SrsConfDirective* old_https_api = (old_http_api? old_http_api->get("https") : NULL); - - // DISABLED => ENABLED - if (!get_https_api_enabled(old_https_api) && get_https_api_enabled(new_https_api)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((err = subscribe->on_reload_https_api_enabled()) != srs_success) { - return srs_error_wrap(err, "https api off=>on"); - } - } - srs_trace("reload off=>on https_api success."); - return err; - } - - // ENABLED => DISABLED - if (get_https_api_enabled(old_https_api) && !get_https_api_enabled(new_https_api)) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((err = subscribe->on_reload_https_api_disabled()) != srs_success) { - return srs_error_wrap(err, "https api on=>off"); - } - } - srs_trace("reload https_api on=>off success."); - return err; - } - - // ENABLED => ENABLED (modified) - if (get_https_api_enabled(old_https_api) && get_https_api_enabled(new_https_api) - && !srs_directive_equals(old_https_api, new_https_api) - ) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((err = subscribe->on_reload_https_api_enabled()) != srs_success) { - return srs_error_wrap(err, "https api enabled"); - } - } - srs_trace("reload https api enabled success."); - return err; - } - - srs_trace("reload https_api success, nothing changed."); - return err; -} - srs_error_t SrsConfig::reload_http_stream(SrsConfDirective* old_root) { srs_error_t err = srs_success; @@ -3668,7 +3602,7 @@ srs_error_t SrsConfig::check_normal_config() SrsConfDirective* conf = root->get("http_server"); for (int i = 0; conf && i < (int)conf->directives.size(); i++) { string n = conf->at(i)->name; - if (n != "enabled" && n != "listen" && n != "dir" && n != "crossdomain") { + if (n != "enabled" && n != "listen" && n != "dir" && n != "crossdomain" && n != "https") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal http_stream.%s", n.c_str()); } } @@ -7737,10 +7671,11 @@ SrsConfDirective* SrsConfig::get_https_api() return conf->get("https"); } -bool SrsConfig::get_https_api_enabled(SrsConfDirective* conf) +bool SrsConfig::get_https_api_enabled() { static bool DEFAULT = false; + SrsConfDirective* conf = get_https_api(); if (!conf) { return DEFAULT; } @@ -7753,15 +7688,9 @@ bool SrsConfig::get_https_api_enabled(SrsConfDirective* conf) return SRS_CONF_PERFER_FALSE(conf->arg0()); } -bool SrsConfig::get_https_api_enabled() -{ - SrsConfDirective* conf = get_https_api(); - return get_https_api_enabled(conf); -} - string SrsConfig::get_https_api_listen() { - static string DEFAULT = "1986"; + static string DEFAULT = "1990"; SrsConfDirective* conf = get_https_api(); if (!conf) { @@ -8097,6 +8026,84 @@ bool SrsConfig::get_http_stream_crossdomain() return SRS_CONF_PERFER_TRUE(conf->arg0()); } +SrsConfDirective* SrsConfig::get_https_stream() +{ + SrsConfDirective* conf = root->get("http_server"); + if (!conf) { + return NULL; + } + + return conf->get("https"); +} + +bool SrsConfig::get_https_stream_enabled() +{ + static bool DEFAULT = false; + + SrsConfDirective* conf = get_https_stream(); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("enabled"); + if (!conf) { + return DEFAULT; + } + + return SRS_CONF_PERFER_FALSE(conf->arg0()); +} + +string SrsConfig::get_https_stream_listen() +{ + static string DEFAULT = "8088"; + + SrsConfDirective* conf = get_https_stream(); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("listen"); + if (!conf) { + return DEFAULT; + } + + return conf->arg0(); +} + +string SrsConfig::get_https_stream_ssl_key() +{ + static string DEFAULT = "./conf/server.key"; + + SrsConfDirective* conf = get_https_stream(); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("key"); + if (!conf) { + return DEFAULT; + } + + return conf->arg0(); +} + +string SrsConfig::get_https_stream_ssl_cert() +{ + static string DEFAULT = "./conf/server.crt"; + + SrsConfDirective* conf = get_https_stream(); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("cert"); + if (!conf) { + return DEFAULT; + } + + return conf->arg0(); +} + bool SrsConfig::get_vhost_http_enabled(string vhost) { static bool DEFAULT = false; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 93d8a85b8..d1e3da877 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -330,7 +330,6 @@ protected: private: // Reload the http_api section of config. virtual srs_error_t reload_http_api(SrsConfDirective* old_root); - virtual srs_error_t reload_https_api(SrsConfDirective* old_root); // Reload the http_stream section of config. // TODO: FIXME: rename to http_server. virtual srs_error_t reload_http_stream(SrsConfDirective* old_root); @@ -1018,7 +1017,6 @@ public: // https api section private: SrsConfDirective* get_https_api(); - virtual bool get_https_api_enabled(SrsConfDirective* conf); public: virtual bool get_https_api_enabled(); virtual std::string get_https_api_listen(); @@ -1038,6 +1036,14 @@ public: virtual std::string get_http_stream_dir(); // Whether enable crossdomain for http static and stream server. virtual bool get_http_stream_crossdomain(); +// https api section +private: + SrsConfDirective* get_https_stream(); +public: + virtual bool get_https_stream_enabled(); + virtual std::string get_https_stream_listen(); + virtual std::string get_https_stream_ssl_key(); + virtual std::string get_https_stream_ssl_cert(); public: // Get whether vhost enabled http stream virtual bool get_vhost_http_enabled(std::string vhost); diff --git a/trunk/src/app/srs_app_conn.cpp b/trunk/src/app/srs_app_conn.cpp index 817b010d2..7717371ba 100644 --- a/trunk/src/app/srs_app_conn.cpp +++ b/trunk/src/app/srs_app_conn.cpp @@ -510,7 +510,7 @@ SrsSslConnection::~SrsSslConnection() } } -srs_error_t SrsSslConnection::handshake() +srs_error_t SrsSslConnection::handshake(string key_file, string crt_file) { srs_error_t err = srs_success; @@ -547,12 +547,10 @@ srs_error_t SrsSslConnection::handshake() int r0, r1, size; // Setup the key and cert file for server. - string crt_file = _srs_config->get_https_api_ssl_cert(); if ((r0 = SSL_use_certificate_file(ssl, crt_file.c_str(), SSL_FILETYPE_PEM)) != 1) { return srs_error_new(ERROR_HTTPS_KEY_CRT, "use cert %s", crt_file.c_str()); } - string key_file = _srs_config->get_https_api_ssl_key(); if ((r0 = SSL_use_RSAPrivateKey_file(ssl, key_file.c_str(), SSL_FILETYPE_PEM)) != 1) { return srs_error_new(ERROR_HTTPS_KEY_CRT, "use key %s", key_file.c_str()); } @@ -759,8 +757,9 @@ srs_error_t SrsSslConnection::writev(const iovec *iov, int iov_size, ssize_t* nw srs_error_t err = srs_success; for (int i = 0; i < iov_size; i++) { - if ((err = write((void*)iov->iov_base, (size_t)iov->iov_len, nwrite)) != srs_success) { - return srs_error_wrap(err, "write iov base=%p, size=%d", iov->iov_base, iov->iov_len); + const iovec* p = iov + i; + if ((err = write((void*)p->iov_base, (size_t)p->iov_len, nwrite)) != srs_success) { + return srs_error_wrap(err, "write iov #%d base=%p, size=%d", i, p->iov_base, p->iov_len); } } diff --git a/trunk/src/app/srs_app_conn.hpp b/trunk/src/app/srs_app_conn.hpp index cace1ad08..ea2e30f7e 100644 --- a/trunk/src/app/srs_app_conn.hpp +++ b/trunk/src/app/srs_app_conn.hpp @@ -178,7 +178,7 @@ public: SrsSslConnection(ISrsProtocolReadWriter* c); virtual ~SrsSslConnection(); public: - virtual srs_error_t handshake(); + virtual srs_error_t handshake(std::string key_file, std::string crt_file); // Interface ISrsProtocolReadWriter public: virtual void set_recv_timeout(srs_utime_t tm); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 95772dddd..b83fd9899 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -1703,7 +1703,10 @@ srs_error_t SrsHttpApi::on_start() { srs_error_t err = srs_success; - if (ssl && (err = ssl->handshake()) != srs_success) { + srs_utime_t starttime = srs_update_system_time(); + string crt_file = _srs_config->get_https_api_ssl_cert(); + string key_file = _srs_config->get_https_api_ssl_key(); + if (ssl && (err = ssl->handshake(key_file, crt_file)) != srs_success) { return srs_error_wrap(err, "handshake"); } @@ -1711,6 +1714,10 @@ srs_error_t SrsHttpApi::on_start() return srs_error_wrap(err, "set jsonp"); } + int cost = srsu2msi(srs_update_system_time() - starttime); + srs_trace("https: api server done, use key %s and cert %s, cost=%dms", + key_file.c_str(), crt_file.c_str(), cost); + return err; } diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 9b6650111..8950ad9a9 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -303,11 +303,18 @@ void SrsHttpConn::expire() trd->interrupt(); } -SrsResponseOnlyHttpConn::SrsResponseOnlyHttpConn(ISrsResourceManager* cm, srs_netfd_t fd, ISrsHttpServeMux* m, string cip, int port) +SrsResponseOnlyHttpConn::SrsResponseOnlyHttpConn(bool https, ISrsResourceManager* cm, srs_netfd_t fd, ISrsHttpServeMux* m, string cip, int port) { manager = cm; skt = new SrsTcpConnection(fd); - conn = new SrsHttpConn(this, skt, m, cip, port); + + if (https) { + ssl = new SrsSslConnection(skt); + conn = new SrsHttpConn(this, ssl, m, cip, port); + } else { + ssl = NULL; + conn = new SrsHttpConn(this, skt, m, cip, port); + } _srs_config->subscribe(this); } @@ -317,6 +324,7 @@ SrsResponseOnlyHttpConn::~SrsResponseOnlyHttpConn() _srs_config->unsubscribe(this); srs_freep(conn); + srs_freep(ssl); srs_freep(skt); } @@ -324,8 +332,13 @@ srs_error_t SrsResponseOnlyHttpConn::pop_message(ISrsHttpMessage** preq) { srs_error_t err = srs_success; + ISrsProtocolReadWriter* io = skt; + if (ssl) { + io = ssl; + } + // Check user interrupt by interval. - skt->set_recv_timeout(3 * SRS_UTIME_SECONDS); + io->set_recv_timeout(3 * SRS_UTIME_SECONDS); // We start a socket to read the stfd, which is writing by conn. // It's ok, because conn never read it after processing the HTTP request. @@ -336,7 +349,7 @@ srs_error_t SrsResponseOnlyHttpConn::pop_message(ISrsHttpMessage** preq) return srs_error_wrap(err, "timeout"); } - if ((err = skt->read(body, 4096, NULL)) != srs_success) { + if ((err = io->read(body, 4096, NULL)) != srs_success) { // Because we use timeout to check trd state, so we should ignore any timeout. if (srs_error_code(err) == ERROR_SOCKET_TIMEOUT) { srs_freep(err); @@ -358,12 +371,31 @@ srs_error_t SrsResponseOnlyHttpConn::on_reload_http_stream_crossdomain() srs_error_t SrsResponseOnlyHttpConn::on_start() { - return srs_success; + srs_error_t err = srs_success; + + srs_utime_t starttime = srs_update_system_time(); + string crt_file = _srs_config->get_https_stream_ssl_cert(); + string key_file = _srs_config->get_https_stream_ssl_key(); + if (ssl && (err = ssl->handshake(key_file, crt_file)) != srs_success) { + return srs_error_wrap(err, "handshake"); + } + + int cost = srsu2msi(srs_update_system_time() - starttime); + srs_trace("https: stream server done, use key %s and cert %s, cost=%dms", + key_file.c_str(), crt_file.c_str(), cost); + + return err; } srs_error_t SrsResponseOnlyHttpConn::on_http_message(ISrsHttpMessage* r, SrsHttpResponseWriter* w) { srs_error_t err = srs_success; + + // After parsed the message, set the schema to https. + if (ssl) { + SrsHttpMessage* hm = dynamic_cast(r); + hm->set_https(true); + } ISrsHttpResponseReader* br = r->body_reader(); @@ -410,7 +442,10 @@ srs_error_t SrsResponseOnlyHttpConn::set_socket_buffer(srs_utime_t buffer_v) std::string SrsResponseOnlyHttpConn::desc() { - return "ROHttpConn"; + if (ssl) { + return "HttpsStream"; + } + return "HttpStream"; } std::string SrsResponseOnlyHttpConn::remote_ip() diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 301c043c0..8b97e2dec 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -150,9 +150,10 @@ private: // The manager object to manage the connection. ISrsResourceManager* manager; SrsTcpConnection* skt; + SrsSslConnection* ssl; SrsHttpConn* conn; public: - SrsResponseOnlyHttpConn(ISrsResourceManager* cm, srs_netfd_t fd, ISrsHttpServeMux* m, std::string cip, int port); + SrsResponseOnlyHttpConn(bool https, ISrsResourceManager* cm, srs_netfd_t fd, ISrsHttpServeMux* m, std::string cip, int port); virtual ~SrsResponseOnlyHttpConn(); public: // Directly read a HTTP request message. diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index a18a692aa..cdb0a5f62 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -108,6 +108,8 @@ std::string srs_listener_type2string(SrsListenerType type) return "HTTPS-API"; case SrsListenerHttpStream: return "HTTP-Server"; + case SrsListenerHttpsStream: + return "HTTP-Server"; case SrsListenerMpegTsOverUdp: return "MPEG-TS over UDP"; case SrsListenerRtsp: @@ -711,6 +713,7 @@ void SrsServer::dispose() close_listeners(SrsListenerHttpApi); close_listeners(SrsListenerHttpsApi); close_listeners(SrsListenerHttpStream); + close_listeners(SrsListenerHttpsStream); close_listeners(SrsListenerMpegTsOverUdp); close_listeners(SrsListenerRtsp); close_listeners(SrsListenerFlv); @@ -741,6 +744,7 @@ void SrsServer::gracefully_dispose() close_listeners(SrsListenerHttpApi); close_listeners(SrsListenerHttpsApi); close_listeners(SrsListenerHttpStream); + close_listeners(SrsListenerHttpsStream); close_listeners(SrsListenerMpegTsOverUdp); close_listeners(SrsListenerRtsp); close_listeners(SrsListenerFlv); @@ -906,6 +910,10 @@ srs_error_t SrsServer::listen() if ((err = listen_http_stream()) != srs_success) { return srs_error_wrap(err, "http stream listen"); } + + if ((err = listen_https_stream()) != srs_success) { + return srs_error_wrap(err, "https stream listen"); + } if ((err = listen_stream_caster()) != srs_success) { return srs_error_wrap(err, "stream caster listen"); @@ -1379,6 +1387,29 @@ srs_error_t SrsServer::listen_http_stream() return err; } +srs_error_t SrsServer::listen_https_stream() +{ + srs_error_t err = srs_success; + + close_listeners(SrsListenerHttpsStream); + if (_srs_config->get_https_stream_enabled()) { + SrsListener* listener = new SrsBufferListener(this, SrsListenerHttpsStream); + listeners.push_back(listener); + + std::string ep = _srs_config->get_https_stream_listen(); + + std::string ip; + int port; + srs_parse_endpoint(ep, ip, port); + + if ((err = listener->listen(ip, port)) != srs_success) { + return srs_error_wrap(err, "https stream listen %s:%d", ip.c_str(), port); + } + } + + return err; +} + #ifdef SRS_GB28181 srs_error_t SrsServer::listen_gb28181_sip(SrsConfDirective* stream_caster) { @@ -1585,7 +1616,9 @@ srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, IS } else if (type == SrsListenerHttpsApi) { *pr = new SrsHttpApi(true, this, stfd, http_api_mux, ip, port); } else if (type == SrsListenerHttpStream) { - *pr = new SrsResponseOnlyHttpConn(this, stfd, http_server, ip, port); + *pr = new SrsResponseOnlyHttpConn(false, this, stfd, http_server, ip, port); + } else if (type == SrsListenerHttpsStream) { + *pr = new SrsResponseOnlyHttpConn(true, this, stfd, http_server, ip, port); } else { srs_warn("close for no service handler. fd=%d, ip=%s:%d", fd, ip.c_str(), port); srs_close_stfd(stfd); @@ -1669,6 +1702,10 @@ srs_error_t SrsServer::on_reload_http_api_enabled() if ((err = listen_http_api()) != srs_success) { return srs_error_wrap(err, "reload http_api"); } + + if ((err = listen_https_api()) != srs_success) { + return srs_error_wrap(err, "reload https_api"); + } return err; } @@ -1676,22 +1713,6 @@ srs_error_t SrsServer::on_reload_http_api_enabled() srs_error_t SrsServer::on_reload_http_api_disabled() { close_listeners(SrsListenerHttpApi); - return srs_success; -} - -srs_error_t SrsServer::on_reload_https_api_enabled() -{ - srs_error_t err = srs_success; - - if ((err = listen_https_api()) != srs_success) { - return srs_error_wrap(err, "reload https_api"); - } - - return err; -} - -srs_error_t SrsServer::on_reload_https_api_disabled() -{ close_listeners(SrsListenerHttpsApi); return srs_success; } @@ -1703,6 +1724,10 @@ srs_error_t SrsServer::on_reload_http_stream_enabled() if ((err = listen_http_stream()) != srs_success) { return srs_error_wrap(err, "reload http_stream enabled"); } + + if ((err = listen_https_stream()) != srs_success) { + return srs_error_wrap(err, "reload https_stream enabled"); + } return err; } @@ -1710,6 +1735,7 @@ srs_error_t SrsServer::on_reload_http_stream_enabled() srs_error_t SrsServer::on_reload_http_stream_disabled() { close_listeners(SrsListenerHttpStream); + close_listeners(SrsListenerHttpsStream); return srs_success; } diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 38ac91cfb..f599c26b4 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -78,6 +78,8 @@ enum SrsListenerType SrsListenerGb28181Sip = 7, // HTTPS api, SrsListenerHttpsApi = 8, + // HTTPS stream, + SrsListenerHttpsStream = 9, }; // A common tcp listener, for RTMP/HTTP server. @@ -325,6 +327,7 @@ private: virtual srs_error_t listen_http_api(); virtual srs_error_t listen_https_api(); virtual srs_error_t listen_http_stream(); + virtual srs_error_t listen_https_stream(); virtual srs_error_t listen_stream_caster(); #ifdef SRS_GB28181 virtual srs_error_t listen_gb28181_sip(SrsConfDirective* c); @@ -359,8 +362,6 @@ public: virtual srs_error_t on_reload_vhost_removed(std::string vhost); virtual srs_error_t on_reload_http_api_enabled(); virtual srs_error_t on_reload_http_api_disabled(); - virtual srs_error_t on_reload_https_api_enabled(); - virtual srs_error_t on_reload_https_api_disabled(); virtual srs_error_t on_reload_http_stream_enabled(); virtual srs_error_t on_reload_http_stream_disabled(); virtual srs_error_t on_reload_http_stream_updated();