check_config函数分析
int SrsConfig::check_config()
{
    int ret = ERROR_SUCCESS;

    srs_trace("srs checking config...");

    ////////////////////////////////////////////////////////////////////////
    // check empty
    ////////////////////////////////////////////////////////////////////////
    if (root->directives.size() == 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("conf is empty, ret=%d", ret);
        return ret;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check root directives.
    ////////////////////////////////////////////////////////////////////////
    for (int i = 0; i < (int)root->directives.size(); i++) {
        SrsConfDirective* conf = root->at(i);
        std::string n = conf->name;
        if (n != "listen" && n != "pid" && n != "chunk_size" && n != "ff_log_dir" 
            && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file"
            && n != "max_connections" && n != "daemon" && n != "heartbeat"
            && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms"
            && n != "http_stream" && n != "http_server" && n != "stream_caster"
            && n != "utc_time" && n != "work_dir" && n != "asprocess"
        ) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("unsupported directive %s, ret=%d", n.c_str(), ret);
            return ret;
        }
    }
    if (true) {
        SrsConfDirective* conf = get_http_api();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "enabled" && n != "listen" && n != "crossdomain") {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported http_api directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    if (true) {
        SrsConfDirective* conf = get_http_stream();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "enabled" && n != "listen" && n != "dir") {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported http_stream directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    if (true) {
        SrsConfDirective* conf = get_heartbeart();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "enabled" && n != "interval" && n != "url"
                && n != "device_id" && n != "summaries"
                ) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported heartbeat directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    if (true) {
        SrsConfDirective* conf = get_stats();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "network" && n != "disk") {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported stats directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    
    
    ////////////////////////////////////////////////////////////////////////
    // check listen for rtmp.
    ////////////////////////////////////////////////////////////////////////
    if (true) {
        vector<string> listens = get_listens();
        if (listens.size() <= 0) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("directive \"listen\" is empty, ret=%d", ret);
            return ret;
        }
        for (int i = 0; i < (int)listens.size(); i++) {
            string port = listens[i];
            if (port.empty() || ::atoi(port.c_str()) <= 0) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("directive listen invalid, port=%s, ret=%d", port.c_str(), ret);
                return ret;
            }
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check max connections
    ////////////////////////////////////////////////////////////////////////
    if (get_max_connections() <= 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive max_connections invalid, max_connections=%d, ret=%d", get_max_connections(), ret);
        return ret;
    }
    
    // check max connections of system limits
    if (true) {
        int nb_consumed_fds = (int)get_listens().size();
        if (!get_http_api_listen().empty()) {
            nb_consumed_fds++;
        }
        if (!get_http_stream_listen().empty()) {
            nb_consumed_fds++;
        }
        if (get_log_tank_file()) {
            nb_consumed_fds++;
        }
        // 0, 1, 2 for stdin, stdout and stderr.
        nb_consumed_fds += 3;
        
        int nb_connections = get_max_connections();
        int nb_total = nb_connections + nb_consumed_fds;
        
        int max_open_files = (int)sysconf(_SC_OPEN_MAX);
        int nb_canbe = max_open_files - nb_consumed_fds - 1;

        // for each play connections, we open a pipe(2fds) to convert SrsConsumver to io,
        // refine performance, @see: https://github.com/ossrs/srs/issues/194
        if (nb_total >= max_open_files) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("invalid max_connections=%d, required=%d, system limit to %d, "
                "total=%d(max_connections=%d, nb_consumed_fds=%d), ret=%d. "
                "you can change max_connections from %d to %d, or "
                "you can login as root and set the limit: ulimit -HSn %d", 
                nb_connections, nb_total + 1, max_open_files, 
                nb_total, nb_connections, nb_consumed_fds,
                ret, nb_connections, nb_canbe, nb_total + 1);
            return ret;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check heartbeat
    ////////////////////////////////////////////////////////////////////////
    if (get_heartbeat_interval() <= 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive heartbeat interval invalid, interval=%"PRId64", ret=%d", 
            get_heartbeat_interval(), ret);
        return ret;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check stats
    ////////////////////////////////////////////////////////////////////////
    if (get_stats_network() < 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive stats network invalid, network=%d, ret=%d", 
            get_stats_network(), ret);
        return ret;
    }
    if (true) {
        vector<std::string> ips = srs_get_local_ipv4_ips();
        int index = get_stats_network();
        if (index >= (int)ips.size()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("stats network invalid, total local ip count=%d, index=%d, ret=%d",
                (int)ips.size(), index, ret);
            return ret;
        }
        srs_warn("stats network use index=%d, ip=%s", index, ips.at(index).c_str());
    }
    if (true) {
        SrsConfDirective* conf = get_stats_disk_device();
        if (conf == NULL || (int)conf->args.size() <= 0) {
            srs_warn("stats disk not configed, disk iops disabled.");
        } else {
            string disks;
            for (int i = 0; i < (int)conf->args.size(); i++) {
                disks += conf->args.at(i);
                disks += " ";
            }
            srs_warn("stats disk list: %s", disks.c_str());
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check http api
    ////////////////////////////////////////////////////////////////////////
    if (get_http_api_listen().empty()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive http_api listen invalid, listen=%s, ret=%d",
            get_http_api_listen().c_str(), ret);
        return ret;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check http stream
    ////////////////////////////////////////////////////////////////////////
    if (get_http_stream_listen().empty()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive http_stream listen invalid, listen=%s, ret=%d",
            get_http_stream_listen().c_str(), ret);
        return ret;
    }
    ////////////////////////////////////////////////////////////////////////
    // check log name and level
    ////////////////////////////////////////////////////////////////////////
    if (true) {
        std::string log_filename = this->get_log_file();
        if (get_log_tank_file() && log_filename.empty()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("must specifies the file to write log to. ret=%d", ret);
            return ret;
        }
        if (get_log_tank_file()) {
            srs_trace("write log to file %s", log_filename.c_str());
            srs_trace("you can: tailf %s", log_filename.c_str());
            srs_trace("@see: %s", SRS_WIKI_URL_LOG);
        } else {
            srs_trace("write log to console");
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check features
    ////////////////////////////////////////////////////////////////////////
#ifndef SRS_AUTO_HTTP_SERVER
    if (get_http_stream_enabled()) {
        srs_warn("http_stream is disabled by configure");
    }
#endif
#ifndef SRS_AUTO_HTTP_API
    if (get_http_api_enabled()) {
        srs_warn("http_api is disabled by configure");
    }
#endif

    vector<SrsConfDirective*> stream_casters = get_stream_casters();
    for (int n = 0; n < (int)stream_casters.size(); n++) {
        SrsConfDirective* stream_caster = stream_casters[n];
        for (int i = 0; stream_caster && i < (int)stream_caster->directives.size(); i++) {
            SrsConfDirective* conf = stream_caster->at(i);
            string n = conf->name;
            if (n != "enabled" && n != "caster" && n != "output"
                && n != "listen" && n != "rtp_port_min" && n != "rtp_port_max"
                ) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported stream_caster directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }

    vector<SrsConfDirective*> vhosts;
    get_vhosts(vhosts);
    for (int n = 0; n < (int)vhosts.size(); n++) {
        SrsConfDirective* vhost = vhosts[n];
        for (int i = 0; vhost && i < (int)vhost->directives.size(); i++) {
            SrsConfDirective* conf = vhost->at(i);
            string n = conf->name;
            if (n != "enabled" && n != "chunk_size"
                && n != "mode" && n != "origin" && n != "token_traverse" && n != "vhost"
                && n != "dvr" && n != "ingest" && n != "hls" && n != "http_hooks"
                && n != "gop_cache" && n != "queue_length"
                && n != "refer" && n != "refer_publish" && n != "refer_play"
                && n != "forward" && n != "transcode" && n != "bandcheck"
                && n != "time_jitter" && n != "mix_correct"
                && n != "atc" && n != "atc_auto"
                && n != "debug_srs_upnode"
                && n != "mr" && n != "mw_latency" && n != "min_latency" && n != "publish"
                && n != "tcp_nodelay" && n != "send_min_interval" && n != "reduce_sequence_header"
                && n != "publish_1stpkt_timeout" && n != "publish_normal_timeout"
                && n != "security" && n != "http_remux"
                && n != "http" && n != "http_static"
                && n != "hds"
            ) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
            // for each sub directives of vhost.
            if (n == "dvr") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "dvr_path" && m != "dvr_plan"
                        && m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost dvr directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "mr") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "latency"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost mr directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "publish") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "parse_sps"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "ingest") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "input" && m != "ffmpeg"
                        && m != "engine"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost ingest directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "http" || n == "http_static") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "mount" && m != "dir") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost http directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "http_remux") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "mount" && m != "fast_cache" && m != "hstrs") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost http_remux directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "hls") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
                        && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
                        && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
                        && m != "hls_wait_keyframe" && m != "hls_dispose"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                    
                    // TODO: FIXME: remove it in future.
                    if (m == "hls_storage" || m == "hls_mount") {
                        srs_warn("HLS RAM is removed from SRS2 to SRS3+, please read https://github.com/ossrs/srs/issues/513.");
                    }
                }
            } else if (n == "http_hooks") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
                        && m != "on_unpublish" && m != "on_play" && m != "on_stop"
                        && m != "on_dvr" && m != "on_hls" && m != "on_hls_notify"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "forward") {
                // TODO: FIXME: implements it.
                /*for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "vhost" && m != "refer") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost forward directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }*/
            } else if (n == "security") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    SrsConfDirective* security = conf->at(j);
                    string m = security->name.c_str();
                    if (m != "enabled" && m != "deny" && m != "allow") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost security directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "transcode") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    SrsConfDirective* trans = conf->at(j);
                    string m = trans->name.c_str();
                    if (m != "enabled" && m != "ffmpeg" && m != "engine") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost transcode directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                    if (m == "engine") {
                        for (int k = 0; k < (int)trans->directives.size(); k++) {
                            string e = trans->at(k)->name;
                            if (e != "enabled" && e != "vfilter" && e != "vcodec"
                                && e != "vbitrate" && e != "vfps" && e != "vwidth" && e != "vheight"
                                && e != "vthreads" && e != "vprofile" && e != "vpreset" && e != "vparams"
                                && e != "acodec" && e != "abitrate" && e != "asample_rate" && e != "achannels"
                                && e != "aparams" && e != "output"
                                && e != "iformat" && e != "oformat"
                                ) {
                                ret = ERROR_SYSTEM_CONFIG_INVALID;
                                srs_error("unsupported vhost transcode engine directive %s, ret=%d", e.c_str(), ret);
                                return ret;
                            }
                        }
                    }
                }
            } else if (n == "bandcheck") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "key" && m != "interval" && m != "limit_kbps") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost bandcheck directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            }
        }
    }
    // check ingest id unique.
    for (int i = 0; i < (int)vhosts.size(); i++) {
        SrsConfDirective* vhost = vhosts[i];
        std::vector<std::string> ids;

        for (int j = 0; j < (int)vhost->directives.size(); j++) {
            SrsConfDirective* conf = vhost->at(j);
            if (conf->name != "ingest") {
                continue;
            }

            std::string id = conf->arg0();
            for (int k = 0; k < (int)ids.size(); k++) {
                if (id == ids.at(k)) {
                    ret = ERROR_SYSTEM_CONFIG_INVALID;
                    srs_error("directive \"ingest\" id duplicated, vhost=%s, id=%s, ret=%d",
                              vhost->name.c_str(), id.c_str(), ret);
                    return ret;
                }
            }
            ids.push_back(id);
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check chunk size
    ////////////////////////////////////////////////////////////////////////
    if (get_global_chunk_size() < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE 
        || get_global_chunk_size() > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE
    ) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", 
            get_global_chunk_size(), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, 
            SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret);
        return ret;
    }
    for (int i = 0; i < (int)vhosts.size(); i++) {
        SrsConfDirective* vhost = vhosts[i];
        if (get_chunk_size(vhost->arg0()) < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE 
            || get_chunk_size(vhost->arg0()) > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE
        ) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("directive vhost %s chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", 
                vhost->arg0().c_str(), get_chunk_size(vhost->arg0()), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, 
                SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret);
            return ret;
        }
    }
    for (int i = 0; i < (int)vhosts.size(); i++) {
        SrsConfDirective* vhost = vhosts[i];
        srs_assert(vhost != NULL);
#ifndef SRS_AUTO_DVR
        if (get_dvr_enabled(vhost->arg0())) {
            srs_warn("dvr of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_HLS
        if (get_hls_enabled(vhost->arg0())) {
            srs_warn("hls of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_HTTP_CALLBACK
        if (get_vhost_http_hooks_enabled(vhost->arg0())) {
            srs_warn("http_hooks of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_TRANSCODE
        if (get_transcode_enabled(get_transcode(vhost->arg0(), ""))) {
            srs_warn("transcode of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_INGEST
        vector<SrsConfDirective*> ingesters = get_ingesters(vhost->arg0());
        for (int j = 0; j < (int)ingesters.size(); j++) {
            SrsConfDirective* ingest = ingesters[j];
            if (get_ingest_enabled(ingest)) {
                srs_warn("ingest %s of vhost %s is disabled by configure", 
                    ingest->arg0().c_str(), vhost->arg0().c_str()
                );
            }
        }
#endif
        // TODO: FIXME: required http server when hls storage is ram or both.
    }
    
    // asprocess conflict with daemon
    if (get_asprocess() && get_deamon()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("daemon conflict with asprocess, ret=%d", ret);
        return ret;
    }
    
    return ret;
}
int SrsConfig::check_config()
{
    int ret = ERROR_SUCCESS;

    srs_trace("srs checking config...");

    ////////////////////////////////////////////////////////////////////////
    // check empty
    ////////////////////////////////////////////////////////////////////////
    if (root->directives.size() == 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("conf is empty, ret=%d", ret);
        return ret;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check root directives.
    ////////////////////////////////////////////////////////////////////////
    for (int i = 0; i < (int)root->directives.size(); i++) {
        SrsConfDirective* conf = root->at(i);
        std::string n = conf->name;
        if (n != "listen" && n != "pid" && n != "chunk_size" && n != "ff_log_dir" 
            && n != "srs_log_tank" && n != "srs_log_level" && n != "srs_log_file"
            && n != "max_connections" && n != "daemon" && n != "heartbeat"
            && n != "http_api" && n != "stats" && n != "vhost" && n != "pithy_print_ms"
            && n != "http_stream" && n != "http_server" && n != "stream_caster"
            && n != "utc_time" && n != "work_dir" && n != "asprocess"
        ) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("unsupported directive %s, ret=%d", n.c_str(), ret);
            return ret;
        }
    }
    if (true) {
        SrsConfDirective* conf = get_http_api();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "enabled" && n != "listen" && n != "crossdomain") {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported http_api directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    if (true) {
        SrsConfDirective* conf = get_http_stream();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "enabled" && n != "listen" && n != "dir") {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported http_stream directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    if (true) {
        SrsConfDirective* conf = get_heartbeart();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "enabled" && n != "interval" && n != "url"
                && n != "device_id" && n != "summaries"
                ) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported heartbeat directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    if (true) {
        SrsConfDirective* conf = get_stats();
        for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
            string n = conf->at(i)->name;
            if (n != "network" && n != "disk") {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported stats directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }
    
    
    ////////////////////////////////////////////////////////////////////////
    // check listen for rtmp.
    ////////////////////////////////////////////////////////////////////////
    if (true) {
        vector<string> listens = get_listens();
        if (listens.size() <= 0) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("directive \"listen\" is empty, ret=%d", ret);
            return ret;
        }
        for (int i = 0; i < (int)listens.size(); i++) {
            string port = listens[i];
            if (port.empty() || ::atoi(port.c_str()) <= 0) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("directive listen invalid, port=%s, ret=%d", port.c_str(), ret);
                return ret;
            }
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check max connections
    ////////////////////////////////////////////////////////////////////////
    if (get_max_connections() <= 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive max_connections invalid, max_connections=%d, ret=%d", get_max_connections(), ret);
        return ret;
    }
    
    // check max connections of system limits
    if (true) {
        int nb_consumed_fds = (int)get_listens().size();
        if (!get_http_api_listen().empty()) {
            nb_consumed_fds++;
        }
        if (!get_http_stream_listen().empty()) {
            nb_consumed_fds++;
        }
        if (get_log_tank_file()) {
            nb_consumed_fds++;
        }
        // 0, 1, 2 for stdin, stdout and stderr.
        nb_consumed_fds += 3;
        
        int nb_connections = get_max_connections();
        int nb_total = nb_connections + nb_consumed_fds;
        
        int max_open_files = (int)sysconf(_SC_OPEN_MAX);
        int nb_canbe = max_open_files - nb_consumed_fds - 1;

        // for each play connections, we open a pipe(2fds) to convert SrsConsumver to io,
        // refine performance, @see: https://github.com/ossrs/srs/issues/194
        if (nb_total >= max_open_files) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("invalid max_connections=%d, required=%d, system limit to %d, "
                "total=%d(max_connections=%d, nb_consumed_fds=%d), ret=%d. "
                "you can change max_connections from %d to %d, or "
                "you can login as root and set the limit: ulimit -HSn %d", 
                nb_connections, nb_total + 1, max_open_files, 
                nb_total, nb_connections, nb_consumed_fds,
                ret, nb_connections, nb_canbe, nb_total + 1);
            return ret;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check heartbeat
    ////////////////////////////////////////////////////////////////////////
    if (get_heartbeat_interval() <= 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive heartbeat interval invalid, interval=%"PRId64", ret=%d", 
            get_heartbeat_interval(), ret);
        return ret;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check stats
    ////////////////////////////////////////////////////////////////////////
    if (get_stats_network() < 0) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive stats network invalid, network=%d, ret=%d", 
            get_stats_network(), ret);
        return ret;
    }
    if (true) {
        vector<std::string> ips = srs_get_local_ipv4_ips();
        int index = get_stats_network();
        if (index >= (int)ips.size()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("stats network invalid, total local ip count=%d, index=%d, ret=%d",
                (int)ips.size(), index, ret);
            return ret;
        }
        srs_warn("stats network use index=%d, ip=%s", index, ips.at(index).c_str());
    }
    if (true) {
        SrsConfDirective* conf = get_stats_disk_device();
        if (conf == NULL || (int)conf->args.size() <= 0) {
            srs_warn("stats disk not configed, disk iops disabled.");
        } else {
            string disks;
            for (int i = 0; i < (int)conf->args.size(); i++) {
                disks += conf->args.at(i);
                disks += " ";
            }
            srs_warn("stats disk list: %s", disks.c_str());
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check http api
    ////////////////////////////////////////////////////////////////////////
    if (get_http_api_listen().empty()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive http_api listen invalid, listen=%s, ret=%d",
            get_http_api_listen().c_str(), ret);
        return ret;
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check http stream
    ////////////////////////////////////////////////////////////////////////
    if (get_http_stream_listen().empty()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive http_stream listen invalid, listen=%s, ret=%d",
            get_http_stream_listen().c_str(), ret);
        return ret;
    }
    ////////////////////////////////////////////////////////////////////////
    // check log name and level
    ////////////////////////////////////////////////////////////////////////
    if (true) {
        std::string log_filename = this->get_log_file();
        if (get_log_tank_file() && log_filename.empty()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("must specifies the file to write log to. ret=%d", ret);
            return ret;
        }
        if (get_log_tank_file()) {
            srs_trace("write log to file %s", log_filename.c_str());
            srs_trace("you can: tailf %s", log_filename.c_str());
            srs_trace("@see: %s", SRS_WIKI_URL_LOG);
        } else {
            srs_trace("write log to console");
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check features
    ////////////////////////////////////////////////////////////////////////
#ifndef SRS_AUTO_HTTP_SERVER
    if (get_http_stream_enabled()) {
        srs_warn("http_stream is disabled by configure");
    }
#endif
#ifndef SRS_AUTO_HTTP_API
    if (get_http_api_enabled()) {
        srs_warn("http_api is disabled by configure");
    }
#endif

    vector<SrsConfDirective*> stream_casters = get_stream_casters();
    for (int n = 0; n < (int)stream_casters.size(); n++) {
        SrsConfDirective* stream_caster = stream_casters[n];
        for (int i = 0; stream_caster && i < (int)stream_caster->directives.size(); i++) {
            SrsConfDirective* conf = stream_caster->at(i);
            string n = conf->name;
            if (n != "enabled" && n != "caster" && n != "output"
                && n != "listen" && n != "rtp_port_min" && n != "rtp_port_max"
                ) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported stream_caster directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
        }
    }

    vector<SrsConfDirective*> vhosts;
    get_vhosts(vhosts);
    for (int n = 0; n < (int)vhosts.size(); n++) {
        SrsConfDirective* vhost = vhosts[n];
        for (int i = 0; vhost && i < (int)vhost->directives.size(); i++) {
            SrsConfDirective* conf = vhost->at(i);
            string n = conf->name;
            if (n != "enabled" && n != "chunk_size"
                && n != "mode" && n != "origin" && n != "token_traverse" && n != "vhost"
                && n != "dvr" && n != "ingest" && n != "hls" && n != "http_hooks"
                && n != "gop_cache" && n != "queue_length"
                && n != "refer" && n != "refer_publish" && n != "refer_play"
                && n != "forward" && n != "transcode" && n != "bandcheck"
                && n != "time_jitter" && n != "mix_correct"
                && n != "atc" && n != "atc_auto"
                && n != "debug_srs_upnode"
                && n != "mr" && n != "mw_latency" && n != "min_latency" && n != "publish"
                && n != "tcp_nodelay" && n != "send_min_interval" && n != "reduce_sequence_header"
                && n != "publish_1stpkt_timeout" && n != "publish_normal_timeout"
                && n != "security" && n != "http_remux"
                && n != "http" && n != "http_static"
                && n != "hds"
            ) {
                ret = ERROR_SYSTEM_CONFIG_INVALID;
                srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret);
                return ret;
            }
            // for each sub directives of vhost.
            if (n == "dvr") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "dvr_path" && m != "dvr_plan"
                        && m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost dvr directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "mr") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "latency"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost mr directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "publish") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "parse_sps"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost publish directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "ingest") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "input" && m != "ffmpeg"
                        && m != "engine"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost ingest directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "http" || n == "http_static") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "mount" && m != "dir") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost http directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "http_remux") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "mount" && m != "fast_cache" && m != "hstrs") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost http_remux directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "hls") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "hls_entry_prefix" && m != "hls_path" && m != "hls_fragment" && m != "hls_window" && m != "hls_on_error"
                        && m != "hls_storage" && m != "hls_mount" && m != "hls_td_ratio" && m != "hls_aof_ratio" && m != "hls_acodec" && m != "hls_vcodec"
                        && m != "hls_m3u8_file" && m != "hls_ts_file" && m != "hls_ts_floor" && m != "hls_cleanup" && m != "hls_nb_notify"
                        && m != "hls_wait_keyframe" && m != "hls_dispose"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost hls directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                    
                    // TODO: FIXME: remove it in future.
                    if (m == "hls_storage" || m == "hls_mount") {
                        srs_warn("HLS RAM is removed from SRS2 to SRS3+, please read https://github.com/ossrs/srs/issues/513.");
                    }
                }
            } else if (n == "http_hooks") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
                        && m != "on_unpublish" && m != "on_play" && m != "on_stop"
                        && m != "on_dvr" && m != "on_hls" && m != "on_hls_notify"
                        ) {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "forward") {
                // TODO: FIXME: implements it.
                /*for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "vhost" && m != "refer") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost forward directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }*/
            } else if (n == "security") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    SrsConfDirective* security = conf->at(j);
                    string m = security->name.c_str();
                    if (m != "enabled" && m != "deny" && m != "allow") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost security directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            } else if (n == "transcode") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    SrsConfDirective* trans = conf->at(j);
                    string m = trans->name.c_str();
                    if (m != "enabled" && m != "ffmpeg" && m != "engine") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost transcode directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                    if (m == "engine") {
                        for (int k = 0; k < (int)trans->directives.size(); k++) {
                            string e = trans->at(k)->name;
                            if (e != "enabled" && e != "vfilter" && e != "vcodec"
                                && e != "vbitrate" && e != "vfps" && e != "vwidth" && e != "vheight"
                                && e != "vthreads" && e != "vprofile" && e != "vpreset" && e != "vparams"
                                && e != "acodec" && e != "abitrate" && e != "asample_rate" && e != "achannels"
                                && e != "aparams" && e != "output"
                                && e != "iformat" && e != "oformat"
                                ) {
                                ret = ERROR_SYSTEM_CONFIG_INVALID;
                                srs_error("unsupported vhost transcode engine directive %s, ret=%d", e.c_str(), ret);
                                return ret;
                            }
                        }
                    }
                }
            } else if (n == "bandcheck") {
                for (int j = 0; j < (int)conf->directives.size(); j++) {
                    string m = conf->at(j)->name.c_str();
                    if (m != "enabled" && m != "key" && m != "interval" && m != "limit_kbps") {
                        ret = ERROR_SYSTEM_CONFIG_INVALID;
                        srs_error("unsupported vhost bandcheck directive %s, ret=%d", m.c_str(), ret);
                        return ret;
                    }
                }
            }
        }
    }
    // check ingest id unique.
    for (int i = 0; i < (int)vhosts.size(); i++) {
        SrsConfDirective* vhost = vhosts[i];
        std::vector<std::string> ids;

        for (int j = 0; j < (int)vhost->directives.size(); j++) {
            SrsConfDirective* conf = vhost->at(j);
            if (conf->name != "ingest") {
                continue;
            }

            std::string id = conf->arg0();
            for (int k = 0; k < (int)ids.size(); k++) {
                if (id == ids.at(k)) {
                    ret = ERROR_SYSTEM_CONFIG_INVALID;
                    srs_error("directive \"ingest\" id duplicated, vhost=%s, id=%s, ret=%d",
                              vhost->name.c_str(), id.c_str(), ret);
                    return ret;
                }
            }
            ids.push_back(id);
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    // check chunk size
    ////////////////////////////////////////////////////////////////////////
    if (get_global_chunk_size() < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE 
        || get_global_chunk_size() > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE
    ) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("directive chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", 
            get_global_chunk_size(), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, 
            SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret);
        return ret;
    }
    for (int i = 0; i < (int)vhosts.size(); i++) {
        SrsConfDirective* vhost = vhosts[i];
        if (get_chunk_size(vhost->arg0()) < SRS_CONSTS_RTMP_MIN_CHUNK_SIZE 
            || get_chunk_size(vhost->arg0()) > SRS_CONSTS_RTMP_MAX_CHUNK_SIZE
        ) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("directive vhost %s chunk_size invalid, chunk_size=%d, must in [%d, %d], ret=%d", 
                vhost->arg0().c_str(), get_chunk_size(vhost->arg0()), SRS_CONSTS_RTMP_MIN_CHUNK_SIZE, 
                SRS_CONSTS_RTMP_MAX_CHUNK_SIZE, ret);
            return ret;
        }
    }
    for (int i = 0; i < (int)vhosts.size(); i++) {
        SrsConfDirective* vhost = vhosts[i];
        srs_assert(vhost != NULL);
#ifndef SRS_AUTO_DVR
        if (get_dvr_enabled(vhost->arg0())) {
            srs_warn("dvr of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_HLS
        if (get_hls_enabled(vhost->arg0())) {
            srs_warn("hls of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_HTTP_CALLBACK
        if (get_vhost_http_hooks_enabled(vhost->arg0())) {
            srs_warn("http_hooks of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_TRANSCODE
        if (get_transcode_enabled(get_transcode(vhost->arg0(), ""))) {
            srs_warn("transcode of vhost %s is disabled by configure", vhost->arg0().c_str());
        }
#endif
#ifndef SRS_AUTO_INGEST
        vector<SrsConfDirective*> ingesters = get_ingesters(vhost->arg0());
        for (int j = 0; j < (int)ingesters.size(); j++) {
            SrsConfDirective* ingest = ingesters[j];
            if (get_ingest_enabled(ingest)) {
                srs_warn("ingest %s of vhost %s is disabled by configure", 
                    ingest->arg0().c_str(), vhost->arg0().c_str()
                );
            }
        }
#endif
        // TODO: FIXME: required http server when hls storage is ram or both.
    }
    
    // asprocess conflict with daemon
    if (get_asprocess() && get_deamon()) {
        ret = ERROR_SYSTEM_CONFIG_INVALID;
        srs_error("daemon conflict with asprocess, ret=%d", ret);
        return ret;
    }
    
    return ret;
}
check_config函数主要功能
1. 检查根指令,必须是 listen,pid,chunk_size,ff_log_dir,srs_log_tank,srs_log_level,srs_log_file,max_connections.
daemon,heartbeat,http_api,stats,vhost,pithy_print_ms,http_stream,http_server,stream_caster,utc_time,work_dir,asprocess
2. 检查 http_api 指令的子指令,必须是enabled,listen,crossdomain
3. 检查 http_stream 指令的子指令,必须是enabled,listen,dir
SrsConfDirective* SrsConfig::get_http_stream()
{
    SrsConfDirective* conf = root->get("http_stream");
    // http_stream renamed to http_server in SRS2.
    if (!conf) {
        conf = root->get("http_server");
    }

    return conf;
}

http_stream被http_server替代

4. 检查 heartbeat 指令的子指令,必须是enabled,interval,url,device_id,summaries

5. 检查 stats 指令的子指令,必须是network,disk

6. 检查根指令指定的RTMP监听端口

7. 检查根指令 get_max_connections,没指定的情况下使用 SRS_CONF_DEFAULT_MAX_CONNECTIONS

8. 检测进程需要的最大文件描述符数量有没有超过系统的限制

// check max connections of system limits
    if (true) {
        int nb_consumed_fds = (int)get_listens().size();
        if (!get_http_api_listen().empty()) {
            nb_consumed_fds++;
        }
        if (!get_http_stream_listen().empty()) {
            nb_consumed_fds++;
        }
        if (get_log_tank_file()) {
            nb_consumed_fds++;
        }
        // 0, 1, 2 for stdin, stdout and stderr.
        nb_consumed_fds += 3;
        
        int nb_connections = get_max_connections();
        int nb_total = nb_connections + nb_consumed_fds;
        
        int max_open_files = (int)sysconf(_SC_OPEN_MAX);
        int nb_canbe = max_open_files - nb_consumed_fds - 1;

        // for each play connections, we open a pipe(2fds) to convert SrsConsumver to io,
        // refine performance, @see: https://github.com/ossrs/srs/issues/194
        if (nb_total >= max_open_files) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("invalid max_connections=%d, required=%d, system limit to %d, "
                "total=%d(max_connections=%d, nb_consumed_fds=%d), ret=%d. "
                "you can change max_connections from %d to %d, or "
                "you can login as root and set the limit: ulimit -HSn %d", 
                nb_connections, nb_total + 1, max_open_files, 
                nb_total, nb_connections, nb_consumed_fds,
                ret, nb_connections, nb_canbe, nb_total + 1);
            return ret;
        }
    }
    

9. 检查 heartbeat.interval 和 stats.network

 if (true) {
        vector<std::string> ips = srs_get_local_ipv4_ips();
        int index = get_stats_network();
        if (index >= (int)ips.size()) {
            ret = ERROR_SYSTEM_CONFIG_INVALID;
            srs_error("stats network invalid, total local ip count=%d, index=%d, ret=%d",
                (int)ips.size(), index, ret);
            return ret;
        }
        srs_warn("stats network use index=%d, ip=%s", index, ips.at(index).c_str());
    }
srs_get_local_ipv4_ips返回非lo的网卡ip

10.检查
http_api和http_stream的listen端口
11.检查日志设置
12.检查 stream_caster指令,必须是 enabled,caster,output,listen,rtp_port_min,rtp_port_max
13.检查 vhost配置