Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Config http_api and rtc_server.tcp listen on same port. #4026

Open
suzp1984 opened this issue Apr 14, 2024 · 2 comments
Open

Bug: Config http_api and rtc_server.tcp listen on same port. #4026

suzp1984 opened this issue Apr 14, 2024 · 2 comments
Assignees
Labels
EnglishNative This issue is conveyed exclusively in English.

Comments

@suzp1984
Copy link
Contributor

Describe the bug
I notice http_api & http_server can listen on same endpoint, and rtc_server.tcp & http_server can also listen on same endpoint.

reuse_api_over_server_ = false;
reuse_rtc_over_server_ = false;

But there are a lot of SrsTcpListeners there, can they shared with same endpoints just like reuse_api_over_server_ & reuse_rtc_over_server_?

e.g. can we reuse rtc over http_api?

http_api {
    enabled         on;
    listen          1985;
}
stats {
    network         0;
}
rtc_server {
    enabled on;
    tcp {
        enabled on;
        listen 1985;
    }
    protocol tcp;
    # @see https://ossrs.net/lts/zh-cn/docs/v4/doc/webrtc#config-candidate
    candidate $CANDIDATE;
}

change conf/rtc.tcp.only.conf, let http_api.listen and rtc_server.tcp.listen with same port.
then boot the srs:
./objs/srs -c conf/rtc.tcp.only.conf

HTTP-API listen at tcp://0.0.0.0:1985, fd=10
WebRTC listen at tcp://0.0.0.0:1985, fd=12

I don't think the http_api and webRTC over TCP can still works well in this case.

Version
ALL SRS version

To Reproduce
Steps to reproduce the behavior:
not just rtc_server.tcp.listen conflict with http_api.listen, rtmp can also be configed conflict with http_server.listen.
e.g.

  1. edit to 'trunk/conf/http.hls.conf', rewrite http_server.listen to 1935;
  2. boot srs: ./objs/srs -c conf/http.hls.conf;
  3. visit http://127.0.0.1:1935, the RTMP listener will hijack the connection. the web browser can't get response.

Expected behavior
Disallow tcp listen have same value, except the already supported reuse_api_over_server_ and reuse_rtc_over_server_.
Or support more tcp listener reuse cases, e.g. rtc & http_api, and disallow others conflicts.

Solutions
support reuse TcpListeners, but there are a lot of them:

rtmp_listener_ = new SrsMultipleTcpListeners(this);
api_listener_ = new SrsTcpListener(this);
apis_listener_ = new SrsTcpListener(this);
http_listener_ = new SrsTcpListener(this);
https_listener_ = new SrsTcpListener(this);
webrtc_listener_ = new SrsTcpListener(this);
stream_caster_flv_listener_ = new SrsHttpFlvListener();
stream_caster_mpegts_ = new SrsUdpCasterListener();
exporter_listener_ = new SrsTcpListener(this);

We can do more things, by do support more reuse listen cases, and do more SrsConfig::check_config, then send panic earlier.

@winlinvip winlinvip added the EnglishNative This issue is conveyed exclusively in English. label Apr 14, 2024
@winlinvip
Copy link
Member

winlinvip commented Apr 15, 2024

APIs and WebRTC are capable of functioning together, and the type of protocol can be determined based on the content of the body. If they do not work well together, it is actually due to issues with the software implementation rather than the protocols being unable to recognize each other.

Since the Listener is a mechanism that is continuously patched, it is not considered reasonable. A better approach would be to completely redesign the mechanism of the Listener.

It is important to note that the SRT's listener requires special handling. For reference, see the issue at #3251 (comment). This issue necessitates improvements to the current structure.

TRANS_BY_GPT4

@winlinvip winlinvip self-assigned this Apr 15, 2024
@suzp1984
Copy link
Contributor Author

suzp1984 commented Apr 16, 2024

Let APIs and WebRTC works on same endpoints would be easy, just refer the reuse_rtc_over_server_ code will add this feature, and really make sense, if reuse_api_over_server_ & reuse_rtc_over_server_ can be both true, then why not another reuse_rtc_over_api_? This is a small patch, can introduce a tiny but controllable complexity.

I like the SrsTcpListener's design, it's really light weight, lower-level abstraction and flexible, maybe I didn't know more better one.

One more thing to consider, the listen config, I notice the inconsistence here.

SrsTcpListener* SrsTcpListener::set_endpoint(const std::string& endpoint)
{
std::string ip; int port_;
srs_parse_endpoint(endpoint, ip, port_);
return set_endpoint(ip, port_);
}

void srs_parse_endpoint(string hostport, string& ip, int& port)
{
const size_t pos = hostport.rfind(":"); // Look for ":" from the end, to work with IPv6.
if (pos != std::string::npos) {
if ((pos >= 1) && (hostport[0] == '[') && (hostport[pos - 1] == ']')) {
// Handle IPv6 in RFC 2732 format, e.g. [3ffe:dead:beef::1]:1935
ip = hostport.substr(1, pos - 2);
} else {
// Handle IP address
ip = hostport.substr(0, pos);
}
const string sport = hostport.substr(pos + 1);
port = ::atoi(sport.c_str());
} else {
ip = srs_any_address_for_listener();
port = ::atoi(hostport.c_str());
}
}

// Get the listen port of SRS.
// user can specifies multiple listen ports,
// each args of directive is a listen port.
virtual std::vector<std::string> get_listens();

// Get the http api listen port.
virtual std::string get_http_api_listen();

    virtual std::string get_http_api_listen();
    virtual std::string get_https_api_listen();
    // Get the http stream listen port.
    virtual std::string get_http_stream_listen();
    virtual std::string get_https_stream_listen();
    virtual std::string get_exporter_listen();

For the RTMP, http_api, http_server, the listen config means endpoint = [ip4/6 | any address] + port;

But for the rest of the listens, which means just port number (or just ipv4 loop back address + port number).

    virtual std::vector<std::string> get_listens();
    // Get the listen port of stream caster.
    virtual int get_stream_caster_listen(SrsConfDirective* conf);
    // Get the sip.listen port configuration.
    virtual int get_stream_caster_sip_listen(SrsConfDirective* conf);
    virtual int get_rtc_server_listen();
    virtual int get_rtc_server_tcp_listen();
    // Get the srt service listen port
    virtual unsigned short get_srt_listen_port();

Here is how gb28181 config its listener, I think it lost its flexibility.

srs_error_t SrsGbListener::initialize(SrsConfDirective* conf)
{
srs_error_t err = srs_success;
srs_freep(conf_);
conf_ = conf->copy();
string ip = srs_any_address_for_listener();
if (true) {
int port = _srs_config->get_stream_caster_listen(conf);
media_listener_->set_endpoint(ip, port)->set_label("GB-TCP");
}
bool sip_enabled = _srs_config->get_stream_caster_sip_enable(conf);
if (!sip_enabled) {
return srs_error_new(ERROR_GB_CONFIG, "GB SIP is required");
}
int port = _srs_config->get_stream_caster_sip_listen(conf);
sip_listener_->set_endpoint(ip, port)->set_label("SIP-TCP");
return err;
}

Because srs_any_address_for_listener() will return the ipv4 loopback in priority. I would rather suggest use a string to represent the listen config, at least it have the capacity of ipv6 address and explicit ip addresses (for the machine with multi physical and virtual network interfaces).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
EnglishNative This issue is conveyed exclusively in English.
Projects
None yet
Development

No branches or pull requests

2 participants