ossrs / srs

SRS is a simple, high-efficiency, real-time video server supporting RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH, and GB28181.
https://ossrs.io
MIT License
25.16k stars 5.31k forks source link

memory leak on flash-publish #3620

Closed pythys closed 4 months ago

pythys commented 1 year ago

Description

on SRS both versions 4 and 5 (including minor versions) I get a memory leak when I receive an RTMP stream using the method flash-publish.

Flash publish is identified from the headers:

SrsRtmpConnFMLEPublish = 0x0200
SrsRtmpConnFlashPublish = 0x0201

so it is whenever I receive 0x0201 that the server blows up and is no longer capable of receiving new streams as per the error logs

  1. SRS Version: 5.0.166 (docker)

  2. SRS Log:

The memory leak seems to be happening in 2023-07-11-flash-publish-srs-leak.txt

  1. SRS Config:
listen              1935;
max_connections     1000;
daemon              off;
srs_log_tank        console;
srs_log_level       info; # default is trace
vhost __defaultVhost__ {
    http_hooks {
        enabled         on;
        on_publish      http://127.0.0.1:8085/api/v1/streams/publish; # delegates to ffmpeg
        on_unpublish    http://127.0.0.1:8085/api/v1/streams/unpublish;
    }
}

Replay

simply receive the stream as publish using above streaming header

Expect

The stream should be ingested OR rejected (because not yet implemented), but what happens instead is the memory leak and crash

analysis

My suspicion is the code block related to having AMF commands combined with flash-publish header:

    // process publish event.
    if (msg->header.is_amf0_command() || msg->header.is_amf3_command()) {
        SrsPacket* pkt = NULL;
        if ((err = rtmp->decode_message(msg, &pkt)) != srs_success) {
            return srs_error_wrap(err, "rtmp: decode message");
        }
        SrsAutoFree(SrsPacket, pkt);

        // for flash, any packet is republish.
        if (info->type == SrsRtmpConnFlashPublish) {
            // flash unpublish.
            // TODO: maybe need to support republish.
            srs_trace("flash flash publish finished.");
            return srs_error_new(ERROR_CONTROL_REPUBLISH, "rtmp: republish");
        }

        // for fmle, drop others except the fmle start packet.
        if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
            SrsFMLEStartPacket* unpublish = dynamic_cast<SrsFMLEStartPacket*>(pkt);
            if ((err = rtmp->fmle_unpublish(info->res->stream_id, unpublish->transaction_id)) != srs_success) {
                return srs_error_wrap(err, "rtmp: republish");
            }
            return srs_error_new(ERROR_CONTROL_REPUBLISH, "rtmp: republish");
        }

        srs_trace("fmle ignore AMF0/AMF3 command message.");
        return err;
    }
chundonglinlin commented 1 year ago

Yeah, yes! SRS will firstly identify the connection type of the client by SrsRtmpServer::identify_client. When receiving the message, it determines whether the AMF commands are amf0/amf3 and decides whether to ignore the packet or wait for the client to republish. You can refer to the modification method here.(https://github.com/ossrs/srs/issues/958)

About this question we will discuss further.

winlinvip commented 4 months ago

Dup to https://github.com/ossrs/srs/issues/958#issuecomment-2041227158