For #1657, Support HTTPS API

pull/2023/head
winlin 4 years ago
parent 7916214e27
commit 272ca9d0f6

@ -197,6 +197,23 @@ http_api {
# default: off
allow_update off;
}
# For https_api or HTTPS API.
https {
# Whether enable HTTPS API.
# default: off
enabled on;
# The listen endpoint for HTTPS API.
# default: 1986
listen 1986;
# 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;
}
}
# embedded http server in srs.
# the http streaming config, for HLS/HDS/DASH/HTTPProgressive

@ -0,0 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDOjCCAiICCQDdW9nBokaeVjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJD
TjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzELMAkGA1UECgwC
TWUxCzAJBgNVBAsMAk1lMRIwEAYDVQQDDAlvc3Nycy5uZXQwHhcNMjAxMTA0MDMz
NzA2WhcNMzAxMTAyMDMzNzA2WjBfMQswCQYDVQQGEwJDTjEQMA4GA1UECAwHQmVp
amluZzEQMA4GA1UEBwwHQmVpamluZzELMAkGA1UECgwCTWUxCzAJBgNVBAsMAk1l
MRIwEAYDVQQDDAlvc3Nycy5uZXQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDboRBymzLCMS0rpJ0EpBBEtkY3kKETYrAcs3AyJyB8YghrotOeY+Klh1ca
GmUMy2UncOBxZKHeupNEytOBWmdk67nrWVc5+nIWoWkqyzSkRFwzE+XbuCbZYjpF
O/G0/aka71mQyuI9W6djhxFUGPctM9ixSYF14/BkuYYDYrW0hXT5PWu0mxleVZAZ
UQsy8DLhwjj9Vn3Y3D6Ttrdax5DHH+WoPmC3L7wrgfpn0ccE8UrvkxvkUJL7pgHN
4n+21lXhrpoH6PP7TLU3Y7cq6XXNlApoitcjxKBBKKKP1jHEN5v8FKCGN0yQuGI2
Pf+ZmuqUnWiDIjQeStknckdmliNnAgMBAAEwDQYJKoZIhvcNAQELBQADggEBABvp
HMf97otfELZBTrk/YbeosgSbyRcxVIUN9nYT06s948katw/bmDABhoslI5ePlomq
X9NrfMEz6eeFIQUOd7KKcfp/sz3nmlkykR5hLe10RxGlB2pwV+Piu9hQfP59y2X8
7hWkT5CbtN8Jm2U151AkZkbEnKVnAbz9XS352Ta5M8AuJGp+rNcFOFZhaMG23kt3
oqZMdehI3RO5CcIiWr/lsX+ZwcDpT+x0DC6F3lBw9r9hBv4pVSP4WZ+zuUCaano8
BCT/FmoxUWMpusGIkhNTNJGAOH1tgtZkiIfiKCKuyHX32sLQ0ls1PUTLqbKubIlS
fYGN4X/2UKfFCXKrNes=
-----END CERTIFICATE-----

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA26EQcpsywjEtK6SdBKQQRLZGN5ChE2KwHLNwMicgfGIIa6LT
nmPipYdXGhplDMtlJ3DgcWSh3rqTRMrTgVpnZOu561lXOfpyFqFpKss0pERcMxPl
27gm2WI6RTvxtP2pGu9ZkMriPVunY4cRVBj3LTPYsUmBdePwZLmGA2K1tIV0+T1r
tJsZXlWQGVELMvAy4cI4/VZ92Nw+k7a3WseQxx/lqD5gty+8K4H6Z9HHBPFK75Mb
5FCS+6YBzeJ/ttZV4a6aB+jz+0y1N2O3Kul1zZQKaIrXI8SgQSiij9YxxDeb/BSg
hjdMkLhiNj3/mZrqlJ1ogyI0HkrZJ3JHZpYjZwIDAQABAoIBAHMEcUmjjzx1ZnNx
nK0+giqJzlHxEvnE9/e/3OTW6sNYz5IWzn4nTx1iuDG6WusNZWb3TQL1MXQj/1XK
ZmNahcUrUc03l1+MkczaMOoxStsv1Z0GMZ0UXnv/Xga98sHXCYVKjXwvU7XQVuPf
ayrAfEmW2kdV+E9V1KHbKpyBSClFtmGTCL7lFq2F+fokTDxItZNDQbkrCTPDa8sR
i4gk/vKi48AJgbnJC2uF9/0+NMJhMjRvpJ8U2roYWd8HQMuJZXYbLPwUDZDMW+rq
l6oax+GZQhrez9bJESrmWZebrJLcJMOhMHv9hVAh8Yu4Bzqhxxsrmjff5PmHIE+t
Upf4J2ECgYEA80Fs6rqbHrrNfNXGolM8h3e9wQyrpWXZnS+OBS1poosns5YalF6g
s1J/GF/lwPs7bQNsX/JSX9NTezKi326qrzbu67K8dxufPNliI10/XlYpOFJRD48m
2ShYUezbA3AipmOiS/Tr4OO0D4uZ4Uo6ThiOEZgM/Eq2vkLX8IKjAxECgYEA5yLC
JJM7Lyr7X2HHAPGBwUyMWVrmbNcECTlk4MxYCY1EKZr+1zgN3Z5do927gqLQYRWH
B3/cAl5en+HTF3aWHPw2CiDsW6jzmgrhHnQOZngh3dGgQN3hFJ5TZy97851gQrsI
xv6dEH/uzl51SKZbS4KccDczdySHu1Za75xvTvcCgYBUIUqUHBnOFPlAtYbPWU5T
49viyokK2SDcNjg+HiisqMgAWmey7M9TdbKzMWd6yOkSmN6AiIRo0+PJdgfSkqnB
k5QqPFTmNM1r9Br29CcYb2AuNHoIkY/0BvoUy4ArvjqdpVPaRUjXLKl3vuZnfo6P
t/pap2XGU+jEAMZCTkwmoQKBgQClPp5aE8CuWiZY7MifjgncLmPwxiITEi3agmPy
q2UNfyeKLzueln6jQMNlkfKq1MfxgLiGzgx2zQ0NdR+7mJZ9pnrkBuG0Ljfqm3iS
kxpwe9aKhYHyni561S5/iN0vMAZP7vO5gPK9hxkuBS4IgJaoh3pcZ7qtpTo83uIo
iEizxQKBgQDpHcsuZy4ZNAQLDnQXjFut3Pypy80NkpThCjOa6yEdleBY9CqttD0K
olVoFQ5h5dv95oBdM5TaKkQNhKDFpLG0vOYRCua7k+xfnDt5Faaiy6Qe/e7cDKbf
9QDejoY43wlEtYzwfSeojnvP0ASPwiWb8DLfBpE0uOTs8/N8qwRiBA==
-----END RSA PRIVATE KEY-----

@ -1538,6 +1538,11 @@ 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) {
@ -1637,6 +1642,67 @@ 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<ISrsReloadHandler*>::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;
@ -3584,7 +3650,7 @@ srs_error_t SrsConfig::check_normal_config()
for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
SrsConfDirective* obj = conf->at(i);
string n = obj->name;
if (n != "enabled" && n != "listen" && n != "crossdomain" && n != "raw_api") {
if (n != "enabled" && n != "listen" && n != "crossdomain" && n != "raw_api" && n != "https") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal http_api.%s", n.c_str());
}
@ -7661,6 +7727,84 @@ bool SrsConfig::get_raw_api_allow_update()
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
SrsConfDirective* SrsConfig::get_https_api()
{
SrsConfDirective* conf = root->get("http_api");
if (!conf) {
return NULL;
}
return conf->get("https");
}
bool SrsConfig::get_https_api_enabled(SrsConfDirective* conf)
{
static bool DEFAULT = false;
conf = conf->get("enabled");
if (!conf) {
return DEFAULT;
}
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";
SrsConfDirective* conf = get_https_api();
if (!conf) {
return DEFAULT;
}
conf = conf->get("listen");
if (!conf) {
return DEFAULT;
}
return conf->arg0();
}
string SrsConfig::get_https_api_ssl_key()
{
static string DEFAULT = "./conf/server.key";
SrsConfDirective* conf = get_https_api();
if (!conf) {
return DEFAULT;
}
conf = conf->get("key");
if (!conf) {
return DEFAULT;
}
return conf->arg0();
}
string SrsConfig::get_https_api_ssl_cert()
{
static string DEFAULT = "./conf/server.crt";
SrsConfDirective* conf = get_https_api();
if (!conf) {
return DEFAULT;
}
conf = conf->get("cert");
if (!conf) {
return DEFAULT;
}
return conf->arg0();
}
bool SrsConfig::get_srt_enabled()
{

@ -330,6 +330,7 @@ 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);
@ -1014,6 +1015,15 @@ public:
virtual bool get_raw_api_allow_query();
// Whether allow rpc update.
virtual bool get_raw_api_allow_update();
// 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();
virtual std::string get_https_api_ssl_key();
virtual std::string get_https_api_ssl_cert();
// http stream section
private:
// Whether http stream enabled.

@ -33,6 +33,8 @@ using namespace std;
#include <srs_kernel_utility.hpp>
#include <srs_service_log.hpp>
#include <srs_app_log.hpp>
#include <srs_app_config.hpp>
#include <srs_core_autofree.hpp>
ISrsDisposingHandler::ISrsDisposingHandler()
{
@ -487,3 +489,281 @@ srs_error_t SrsTcpConnection::writev(const iovec *iov, int iov_size, ssize_t* nw
return skt->writev(iov, iov_size, nwrite);
}
SrsSslConnection::SrsSslConnection(ISrsProtocolReadWriter* c)
{
transport = c;
ssl_ctx = NULL;
ssl = NULL;
}
SrsSslConnection::~SrsSslConnection()
{
if (ssl) {
// this function will free bio_in and bio_out
SSL_free(ssl);
ssl = NULL;
}
if (ssl_ctx) {
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
}
srs_error_t SrsSslConnection::handshake()
{
srs_error_t err = srs_success;
// For HTTPS, try to connect over security transport.
#if (OPENSSL_VERSION_NUMBER < 0x10002000L) // v1.0.2
ssl_ctx = SSL_CTX_new(TLS_method());
#else
ssl_ctx = SSL_CTX_new(TLSv1_2_method());
#endif
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
srs_assert(SSL_CTX_set_cipher_list(ssl_ctx, "ALL") == 1);
// TODO: Setup callback, see SSL_set_ex_data and SSL_set_info_callback
if ((ssl = SSL_new(ssl_ctx)) == NULL) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "SSL_new ssl");
}
if ((bio_in = BIO_new(BIO_s_mem())) == NULL) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_new in");
}
if ((bio_out = BIO_new(BIO_s_mem())) == NULL) {
BIO_free(bio_in);
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_new out");
}
SSL_set_bio(ssl, bio_in, bio_out);
// SSL setup active, as server role.
SSL_set_accept_state(ssl);
SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
uint8_t* data = NULL;
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());
}
if ((r0 = SSL_check_private_key(ssl)) != 1) {
return srs_error_new(ERROR_HTTPS_KEY_CRT, "check key %s with cert %s",
key_file.c_str(), crt_file.c_str());
}
srs_info("ssl: use key %s and cert %s", key_file.c_str(), crt_file.c_str());
// Receive ClientHello
while (true) {
char buf[1024]; ssize_t nn = 0;
if ((err = transport->read(buf, sizeof(buf), &nn)) != srs_success) {
return srs_error_wrap(err, "handshake: read");
}
if ((r0 = BIO_write(bio_in, buf, nn)) <= 0) {
// TODO: 0 or -1 maybe block, use BIO_should_retry to check.
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_write r0=%d, data=%p, size=%d", r0, buf, nn);
}
r0 = SSL_do_handshake(ssl); r1 = SSL_get_error(ssl, r0);
if (r0 != -1 || r1 != SSL_ERROR_WANT_READ) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "handshake r0=%d, r1=%d", r0, r1);
}
if ((size = BIO_get_mem_data(bio_out, &data)) > 0) {
// OK, reset it for the next write.
if ((r0 = BIO_reset(bio_in)) != 1) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_reset r0=%d", r0);
}
break;
}
}
srs_info("https: ClientHello done");
// Send ServerHello, Certificate, Server Key Exchange, Server Hello Done
size = BIO_get_mem_data(bio_out, &data);
if (!data || size <= 0) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "handshake data=%p, size=%d", data, size);
}
if ((err = transport->write(data, size, NULL)) != srs_success) {
return srs_error_wrap(err, "handshake: write data=%p, size=%d", data, size);
}
if ((r0 = BIO_reset(bio_out)) != 1) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_reset r0=%d", r0);
}
srs_info("https: ServerHello done");
// Receive Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
while (true) {
char buf[1024]; ssize_t nn = 0;
if ((err = transport->read(buf, sizeof(buf), &nn)) != srs_success) {
return srs_error_wrap(err, "handshake: read");
}
if ((r0 = BIO_write(bio_in, buf, nn)) <= 0) {
// TODO: 0 or -1 maybe block, use BIO_should_retry to check.
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_write r0=%d, data=%p, size=%d", r0, buf, nn);
}
r0 = SSL_do_handshake(ssl); r1 = SSL_get_error(ssl, r0);
if (r0 == 1 && r1 == SSL_ERROR_NONE) {
break;
}
if (r0 != -1 || r1 != SSL_ERROR_WANT_READ) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "handshake r0=%d, r1=%d", r0, r1);
}
if ((size = BIO_get_mem_data(bio_out, &data)) > 0) {
// OK, reset it for the next write.
if ((r0 = BIO_reset(bio_in)) != 1) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_reset r0=%d", r0);
}
break;
}
}
srs_info("https: Client done");
// Send New Session Ticket, Change Cipher Spec, Encrypted Handshake Message
size = BIO_get_mem_data(bio_out, &data);
if (!data || size <= 0) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "handshake data=%p, size=%d", data, size);
}
if ((err = transport->write(data, size, NULL)) != srs_success) {
return srs_error_wrap(err, "handshake: write data=%p, size=%d", data, size);
}
if ((r0 = BIO_reset(bio_out)) != 1) {
return srs_error_new(ERROR_HTTPS_HANDSHAKE, "BIO_reset r0=%d", r0);
}
srs_info("https: Server done");
return err;
}
void SrsSslConnection::set_recv_timeout(srs_utime_t tm)
{
transport->set_recv_timeout(tm);
}
srs_utime_t SrsSslConnection::get_recv_timeout()
{
return transport->get_recv_timeout();
}
srs_error_t SrsSslConnection::read_fully(void* buf, size_t size, ssize_t* nread)
{
return transport->read_fully(buf, size, nread);
}
int64_t SrsSslConnection::get_recv_bytes()
{
return transport->get_recv_bytes();
}
int64_t SrsSslConnection::get_send_bytes()
{
return transport->get_send_bytes();
}
srs_error_t SrsSslConnection::read(void* plaintext, size_t nn_plaintext, ssize_t* nread)
{
srs_error_t err = srs_success;
// TODO: Can we avoid copy?
int nn_cipher = nn_plaintext;
char* cipher = new char[nn_cipher];
SrsAutoFreeA(char, cipher);
ssize_t nn = 0;
// Read the cipher from SSL.
if ((err = transport->read(cipher, nn_cipher, &nn)) != srs_success) {
return srs_error_wrap(err, "https: read");
}
int r0 = BIO_write(bio_in, cipher, nn);
if (r0 <= 0) {
// TODO: 0 or -1 maybe block, use BIO_should_retry to check.
return srs_error_new(ERROR_HTTPS_READ, "BIO_write r0=%d, cipher=%p, size=%d", r0, cipher, nn);
}
r0 = SSL_read(ssl, plaintext, nn);
if (r0 <= 0) {
return srs_error_new(ERROR_HTTPS_READ, "SSL_read r0=%d, cipher=%p, size=%d", r0, cipher, nn);
}
srs_assert(r0 <= nn_plaintext);
if (nread) {
*nread = r0;
}
return err;
}
void SrsSslConnection::set_send_timeout(srs_utime_t tm)
{
transport->set_send_timeout(tm);
}
srs_utime_t SrsSslConnection::get_send_timeout()
{
return transport->get_send_timeout();
}
srs_error_t SrsSslConnection::write(void* plaintext, size_t nn_plaintext, ssize_t* nwrite)
{
srs_error_t err = srs_success;
for (char* p = (char*)plaintext; p < (char*)plaintext + nn_plaintext;) {
int left = (int)nn_plaintext - (p - (char*)plaintext);
int r0 = SSL_write(ssl, (const void*)p, left);
int r1 = SSL_get_error(ssl, r0);
if (r0 <= 0) {
return srs_error_new(ERROR_HTTPS_WRITE, "https: write data=%p, size=%d, r0=%d, r1=%d", p, left, r0, r1);
}
// Move p to the next writing position.
p += r0;
if (nwrite) {
*nwrite += (ssize_t)r0;
}
uint8_t* data = NULL;
int size = BIO_get_mem_data(bio_out, &data);
if ((err = transport->write(data, size, NULL)) != srs_success) {
return srs_error_wrap(err, "https: write data=%p, size=%d", data, size);
}
if ((r0 = BIO_reset(bio_out)) != 1) {
return srs_error_new(ERROR_HTTPS_WRITE, "BIO_reset r0=%d", r0);
}
}
return err;
}
srs_error_t SrsSslConnection::writev(const iovec *iov, int iov_size, ssize_t* nwrite)
{
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);
}
}
return err;
}

@ -30,6 +30,8 @@
#include <vector>
#include <map>
#include <openssl/ssl.h>
#include <srs_app_st.hpp>
#include <srs_protocol_kbps.hpp>
#include <srs_app_reload.hpp>
@ -161,4 +163,34 @@ public:
virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t* nwrite);
};
// The SSL connection over TCP transport, in server mode.
class SrsSslConnection : virtual public ISrsProtocolReadWriter
{
private:
// The under-layer plaintext transport.
ISrsProtocolReadWriter* transport;
private:
SSL_CTX* ssl_ctx;
SSL* ssl;
BIO* bio_in;
BIO* bio_out;
public:
SrsSslConnection(ISrsProtocolReadWriter* c);
virtual ~SrsSslConnection();
public:
virtual srs_error_t handshake();
// Interface ISrsProtocolReadWriter
public:
virtual void set_recv_timeout(srs_utime_t tm);
virtual srs_utime_t get_recv_timeout();
virtual srs_error_t read_fully(void* buf, size_t size, ssize_t* nread);
virtual int64_t get_recv_bytes();
virtual int64_t get_send_bytes();
virtual srs_error_t read(void* buf, size_t size, ssize_t* nread);
virtual void set_send_timeout(srs_utime_t tm);
virtual srs_utime_t get_send_timeout();
virtual srs_error_t write(void* buf, size_t size, ssize_t* nwrite);
virtual srs_error_t writev(const iovec *iov, int iov_size, ssize_t* nwrite);
};
#endif

@ -1678,7 +1678,14 @@ SrsHttpApi::SrsHttpApi(bool https, ISrsResourceManager* cm, srs_netfd_t fd, SrsH
{
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);
}
@ -1688,6 +1695,7 @@ SrsHttpApi::~SrsHttpApi()
_srs_config->unsubscribe(this);
srs_freep(conn);
srs_freep(ssl);
srs_freep(skt);
}
@ -1695,6 +1703,10 @@ srs_error_t SrsHttpApi::on_start()
{
srs_error_t err = srs_success;
if (ssl && (err = ssl->handshake()) != srs_success) {
return srs_error_wrap(err, "handshake");
}
if ((err = conn->set_jsonp(true)) != srs_success) {
return srs_error_wrap(err, "set jsonp");
}
@ -1706,6 +1718,12 @@ srs_error_t SrsHttpApi::on_http_message(ISrsHttpMessage* r, SrsHttpResponseWrite
{
srs_error_t err = srs_success;
// After parsed the message, set the schema to https.
if (ssl) {
SrsHttpMessage* hm = dynamic_cast<SrsHttpMessage*>(r);
hm->set_https(true);
}
// TODO: For each API session, we use short-term HTTP connection.
//SrsHttpHeader* hdr = w->header();
//hdr->set("Connection", "Close");

@ -263,6 +263,7 @@ private:
// The manager object to manage the connection.
ISrsResourceManager* manager;
SrsTcpConnection* skt;
SrsSslConnection* ssl;
SrsHttpConn* conn;
public:
SrsHttpApi(bool https, ISrsResourceManager* cm, srs_netfd_t fd, SrsHttpServeMux* m, std::string cip, int port);

@ -94,7 +94,6 @@ SrsHttpConn::~SrsHttpConn()
srs_freep(kbps);
srs_freep(clk);
srs_freep(skt);
}
std::string SrsHttpConn::desc()

@ -85,6 +85,16 @@ srs_error_t ISrsReloadHandler::on_reload_http_api_disabled()
return srs_success;
}
srs_error_t ISrsReloadHandler::on_reload_https_api_enabled()
{
return srs_success;
}
srs_error_t ISrsReloadHandler::on_reload_https_api_disabled()
{
return srs_success;
}
srs_error_t ISrsReloadHandler::on_reload_http_api_crossdomain()
{
return srs_success;

@ -49,6 +49,8 @@ public:
virtual srs_error_t on_reload_pithy_print();
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_api_crossdomain();
virtual srs_error_t on_reload_http_api_raw_api();
virtual srs_error_t on_reload_http_stream_enabled();

@ -104,6 +104,8 @@ std::string srs_listener_type2string(SrsListenerType type)
return "RTMP";
case SrsListenerHttpApi:
return "HTTP-API";
case SrsListenerHttpsApi:
return "HTTPS-API";
case SrsListenerHttpStream:
return "HTTP-Server";
case SrsListenerMpegTsOverUdp:
@ -707,6 +709,7 @@ void SrsServer::dispose()
// prevent fresh clients.
close_listeners(SrsListenerRtmpStream);
close_listeners(SrsListenerHttpApi);
close_listeners(SrsListenerHttpsApi);
close_listeners(SrsListenerHttpStream);
close_listeners(SrsListenerMpegTsOverUdp);
close_listeners(SrsListenerRtsp);
@ -736,6 +739,7 @@ void SrsServer::gracefully_dispose()
// prevent fresh clients.
close_listeners(SrsListenerRtmpStream);
close_listeners(SrsListenerHttpApi);
close_listeners(SrsListenerHttpsApi);
close_listeners(SrsListenerHttpStream);
close_listeners(SrsListenerMpegTsOverUdp);
close_listeners(SrsListenerRtsp);
@ -894,6 +898,10 @@ srs_error_t SrsServer::listen()
if ((err = listen_http_api()) != srs_success) {
return srs_error_wrap(err, "http api listen");
}
if ((err = listen_https_api()) != srs_success) {
return srs_error_wrap(err, "https api listen");
}
if ((err = listen_http_stream()) != srs_success) {
return srs_error_wrap(err, "http stream listen");
@ -1325,6 +1333,29 @@ srs_error_t SrsServer::listen_http_api()
return err;
}
srs_error_t SrsServer::listen_https_api()
{
srs_error_t err = srs_success;
close_listeners(SrsListenerHttpsApi);
if (_srs_config->get_https_api_enabled()) {
SrsListener* listener = new SrsBufferListener(this, SrsListenerHttpsApi);
listeners.push_back(listener);
std::string ep = _srs_config->get_https_api_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 api listen %s:%d", ip.c_str(), port);
}
}
return err;
}
srs_error_t SrsServer::listen_http_stream()
{
srs_error_t err = srs_success;
@ -1550,7 +1581,9 @@ srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, IS
if (type == SrsListenerRtmpStream) {
*pr = new SrsRtmpConn(this, stfd, ip, port);
} else if (type == SrsListenerHttpApi) {
*pr = new SrsHttpApi(this, stfd, http_api_mux, ip, port);
*pr = new SrsHttpApi(false, this, stfd, http_api_mux, ip, port);
} 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);
} else {
@ -1646,6 +1679,23 @@ srs_error_t SrsServer::on_reload_http_api_disabled()
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;
}
srs_error_t SrsServer::on_reload_http_stream_enabled()
{
srs_error_t err = srs_success;

@ -76,6 +76,8 @@ enum SrsListenerType
SrsListenerGb28181RtpMux = 6,
// UDP gb28181 sip server
SrsListenerGb28181Sip = 7,
// HTTPS api,
SrsListenerHttpsApi = 8,
};
// A common tcp listener, for RTMP/HTTP server.
@ -321,6 +323,7 @@ private:
// listen at specified protocol.
virtual srs_error_t listen_rtmp();
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_stream_caster();
#ifdef SRS_GB28181
@ -356,6 +359,8 @@ 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();

@ -328,6 +328,7 @@
#define ERROR_HTTPS_HANDSHAKE 4042
#define ERROR_HTTPS_READ 4043
#define ERROR_HTTPS_WRITE 4044
#define ERROR_HTTPS_KEY_CRT 4045
///////////////////////////////////////////////////////
// RTC protocol error.

@ -916,6 +916,17 @@ srs_error_t SrsHttpUri::initialize(string _url)
return err;
}
void SrsHttpUri::set_schema(std::string v)
{
schema = v;
// Update url with new schema.
size_t pos = url.find("://");
if (pos != string::npos) {
url = schema + "://" + url.substr(pos + 3);
}
}
string SrsHttpUri::get_url()
{
return url;

@ -525,6 +525,8 @@ public:
public:
// Initialize the http uri.
virtual srs_error_t initialize(std::string _url);
// After parsed the message, set the schema to https.
virtual void set_schema(std::string v);
public:
virtual std::string get_url();
virtual std::string get_schema();

@ -59,16 +59,16 @@ SrsSslClient::SrsSslClient(SrsTcpClient* tcp)
SrsSslClient::~SrsSslClient()
{
if (ssl_ctx) {
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
if (ssl) {
// this function will free bio_in and bio_out
SSL_free(ssl);
ssl = NULL;
}
if (ssl_ctx) {
SSL_CTX_free(ssl_ctx);
ssl_ctx = NULL;
}
}
srs_error_t SrsSslClient::handshake()
@ -77,9 +77,9 @@ srs_error_t SrsSslClient::handshake()
// For HTTPS, try to connect over security transport.
#if (OPENSSL_VERSION_NUMBER < 0x10002000L) // v1.0.2
SSL_CTX* ssl_ctx = SSL_CTX_new(TLS_method());
ssl_ctx = SSL_CTX_new(TLS_method());
#else
SSL_CTX* ssl_ctx = SSL_CTX_new(TLSv1_2_method());
ssl_ctx = SSL_CTX_new(TLSv1_2_method());
#endif
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, srs_verify_callback);
srs_assert(SSL_CTX_set_cipher_list(ssl_ctx, "ALL") == 1);

@ -414,6 +414,11 @@ srs_error_t SrsHttpMessage::set_url(string url, bool allow_jsonp)
return err;
}
void SrsHttpMessage::set_https(bool v)
{
_uri->set_schema(v? "https" : "http");
}
ISrsConnection* SrsHttpMessage::connection()
{
return owner_conn;

@ -145,6 +145,8 @@ public:
virtual void set_header(SrsHttpHeader* header, bool keep_alive);
// set the original messages, then update the message.
virtual srs_error_t set_url(std::string url, bool allow_jsonp);
// After parsed the message, set the schema to https.
virtual void set_https(bool v);
public:
// Get the owner connection, maybe NULL.
virtual ISrsConnection* connection();

Loading…
Cancel
Save