1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-03-09 15:49:59 +00:00

WebRTC: Extract SrsRtcNetwork layer for UDP/TCP.

This commit is contained in:
winlin 2022-09-03 11:52:11 +08:00
parent 770d959148
commit 625069af7f
23 changed files with 698 additions and 528 deletions

View file

@ -36,7 +36,10 @@ using namespace std;
#include <srs_app_coworkers.hpp>
#include <srs_protocol_log.hpp>
#include <srs_app_latest_version.hpp>
#include <srs_app_conn.hpp>
#ifdef SRS_RTC
#include <srs_app_rtc_network.hpp>
#endif
std::string srs_listener_type2string(SrsListenerType type)
{
@ -533,6 +536,7 @@ SrsServer::SrsServer()
http_api_mux = new SrsHttpServeMux();
http_server = new SrsHttpServer(this);
reuse_api_over_server_ = false;
reuse_rtc_over_server_ = false;
http_heartbeat = new SrsHttpHeartbeat();
ingester = new SrsIngester();
@ -655,16 +659,35 @@ srs_error_t SrsServer::initialize(ISrsServerCycle* ch)
return srs_error_wrap(err, "handler initialize");
}
bool stream = _srs_config->get_http_stream_enabled();
string http_listen = _srs_config->get_http_stream_listen();
string https_listen = _srs_config->get_https_stream_listen();
#ifdef SRS_RTC
bool rtc = _srs_config->get_rtc_server_enabled();
bool rtc_tcp = _srs_config->get_rtc_server_tcp_enabled();
string rtc_listen = srs_int2str(_srs_config->get_rtc_server_tcp_listen());
// If enabled and listen is the same value, resue port for WebRTC over TCP.
if (stream && rtc && rtc_tcp && http_listen == rtc_listen) {
srs_trace("WebRTC tcp=%s reuses http=%s server", rtc_listen.c_str(), http_listen.c_str());
reuse_rtc_over_server_ = true;
}
if (stream && rtc && rtc_tcp && https_listen == rtc_listen) {
srs_trace("WebRTC tcp=%s reuses https=%s server", rtc_listen.c_str(), https_listen.c_str());
reuse_rtc_over_server_ = true;
}
#endif
// If enabled and the listen is the same value, reuse port.
if (_srs_config->get_http_stream_enabled() && _srs_config->get_http_api_enabled()
&& _srs_config->get_http_api_listen() == _srs_config->get_http_stream_listen()
&& _srs_config->get_https_api_listen() == _srs_config->get_https_stream_listen()
) {
srs_trace("API reuse listen to https server at %s", _srs_config->get_https_stream_listen().c_str());
bool api = _srs_config->get_http_api_enabled();
string api_listen = _srs_config->get_http_api_listen();
string apis_listen = _srs_config->get_https_api_listen();
if (stream && api && api_listen == http_listen && apis_listen == https_listen) {
srs_trace("API reuses http=%s and https=%s server", http_listen.c_str(), https_listen.c_str());
reuse_api_over_server_ = true;
}
// If reuse port, use the same object as server.
// Only init HTTP API when not reusing HTTP server.
if (!reuse_api_over_server_) {
SrsHttpServeMux *api = dynamic_cast<SrsHttpServeMux*>(http_api_mux);
srs_assert(api);
@ -744,22 +767,26 @@ srs_error_t SrsServer::listen()
return srs_error_wrap(err, "stream caster listen");
}
// TODO: FIXME: Refine the listeners.
close_listeners(SrsListenerTcp);
if (_srs_config->get_rtc_server_tcp_enabled()) {
SrsListener* listener = new SrsBufferListener(this, SrsListenerTcp);
listeners.push_back(listener);
#ifdef SRS_RTC
if (!reuse_rtc_over_server_) {
// TODO: FIXME: Refine the listeners.
close_listeners(SrsListenerTcp);
if (_srs_config->get_rtc_server_tcp_enabled()) {
SrsListener* listener = new SrsBufferListener(this, SrsListenerTcp);
listeners.push_back(listener);
std::string ep = srs_int2str(_srs_config->get_rtc_server_tcp_listen());
std::string ep = srs_int2str(_srs_config->get_rtc_server_tcp_listen());
std::string ip;
int port;
srs_parse_endpoint(ep, ip, port);
std::string ip;
int port;
srs_parse_endpoint(ep, ip, port);
if ((err = listener->listen(ip, port)) != srs_success) {
return srs_error_wrap(err, "tcp listen %s:%d", ip.c_str(), port);
if ((err = listener->listen(ip, port)) != srs_success) {
return srs_error_wrap(err, "tcp listen %s:%d", ip.c_str(), port);
}
}
}
#endif
if ((err = conn_manager->start()) != srs_success) {
return srs_error_wrap(err, "connection manager");
@ -1376,11 +1403,13 @@ void SrsServer::resample_kbps()
continue;
}
#ifdef SRS_RTC
SrsRtcTcpConn* tcp = dynamic_cast<SrsRtcTcpConn*>(c);
if (tcp) {
stat->kbps_add_delta(c->get_id().c_str(), tcp->delta());
continue;
}
#endif
// Impossible path, because we only create these connections above.
srs_assert(false);
@ -1397,7 +1426,6 @@ srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
ISrsResource* resource = NULL;
if ((err = fd_to_resource(type, stfd, &resource)) != srs_success) {
//close fd on conn error, otherwise will lead to fd leak -gs
srs_close_stfd(stfd);
if (srs_error_code(err) == ERROR_SOCKET_GET_PEER_IP && _srs_config->empty_ip_ok()) {
srs_error_reset(err);
@ -1405,7 +1433,11 @@ srs_error_t SrsServer::accept_client(SrsListenerType type, srs_netfd_t stfd)
}
return srs_error_wrap(err, "fd to resource");
}
srs_assert(resource);
// Ignore if no resource found.
if (!resource) {
return err;
}
// directly enqueue, the cycle thread will remove the client.
conn_manager->add(resource);
@ -1423,7 +1455,7 @@ ISrsHttpServeMux* SrsServer::api_server()
return http_api_mux;
}
srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, ISrsResource** pr)
srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t& stfd, ISrsResource** pr)
{
srs_error_t err = srs_success;
@ -1462,24 +1494,56 @@ srs_error_t SrsServer::fd_to_resource(SrsListenerType type, srs_netfd_t stfd, IS
}
}
// We will free the stfd from now on.
srs_netfd_t fd2 = stfd;
stfd = NULL;
// The context id may change during creating the bellow objects.
SrsContextRestore(_srs_context->get_id());
#ifdef SRS_RTC
// If reuse HTTP server with WebRTC TCP, peek to detect the client.
if (reuse_rtc_over_server_ && (type == SrsListenerHttpStream || type == SrsListenerHttpsStream)) {
SrsTcpConnection* skt = new SrsTcpConnection(fd2);
SrsBufferedReader* io = new SrsBufferedReader(skt);
uint8_t b[10]; int nn = sizeof(b);
if ((err = io->peek((char*)b, &nn)) != srs_success) {
srs_freep(io); srs_freep(skt);
return srs_error_wrap(err, "peek");
}
// If first message is BindingRequest(00 01), prefixed with length(2B), it's WebRTC client. Generally, the frame
// length minus message length should be 20, that is the header size of STUN is 20 bytes. For example:
// 00 6c # Frame length: 0x006c = 108
// 00 01 # Message Type: Binding Request(0x0001)
// 00 58 # Message Length: 0x005 = 88
// 21 12 a4 42 # Message Cookie: 0x2112a442
// 48 32 6c 61 6b 42 35 71 42 35 4a 71 # Message Transaction ID: 12 bytes
if (nn == 10 && b[0] == 0 && b[2] == 0 && b[3] == 1 && b[1] - b[5] == 20
&& b[6] == 0x21 && b[7] == 0x12 && b[8] == 0xa4 && b[9] == 0x42
) {
*pr = new SrsRtcTcpConn(io, ip, port, this);
} else {
*pr = new SrsHttpxConn(type == SrsListenerHttpsStream, this, io, http_server, ip, port);
}
return err;
}
#endif
if (type == SrsListenerRtmpStream) {
*pr = new SrsRtmpConn(this, stfd, ip, port);
} else if (type == SrsListenerHttpApi) {
*pr = new SrsHttpxConn(false, this, stfd, http_api_mux, ip, port);
} else if (type == SrsListenerHttpsApi) {
*pr = new SrsHttpxConn(true, this, stfd, http_api_mux, ip, port);
} else if (type == SrsListenerHttpStream) {
*pr = new SrsHttpxConn(false, this, stfd, http_server, ip, port);
} else if (type == SrsListenerHttpsStream) {
*pr = new SrsHttpxConn(true, this, stfd, http_server, ip, port);
*pr = new SrsRtmpConn(this, fd2, ip, port);
} else if (type == SrsListenerHttpApi || type == SrsListenerHttpsApi) {
*pr = new SrsHttpxConn(type == SrsListenerHttpsApi, this, new SrsTcpConnection(fd2), http_api_mux, ip, port);
} else if (type == SrsListenerHttpStream || type == SrsListenerHttpsStream) {
*pr = new SrsHttpxConn(type == SrsListenerHttpsStream, this, new SrsTcpConnection(fd2), http_server, ip, port);
#ifdef SRS_RTC
} else if (type == SrsListenerTcp) {
*pr = new SrsRtcTcpConn(stfd, ip, port, this);
*pr = new SrsRtcTcpConn(new SrsTcpConnection(fd2), ip, port, this);
#endif
} else {
srs_warn("close for no service handler. fd=%d, ip=%s:%d", fd, ip.c_str(), port);
srs_close_stfd(stfd);
srs_close_stfd(fd2);
return err;
}