// // Copyright (c) 2013-2021 The SRS Authors // // SPDX-License-Identifier: MIT // #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; SrsLatestVersion::SrsLatestVersion() { trd_ = new SrsSTCoroutine("signal", this); } SrsLatestVersion::~SrsLatestVersion() { srs_freep(trd_); } srs_error_t SrsLatestVersion::start() { if (!_srs_config->whether_query_latest_version()) { return srs_success; } server_id_ = srs_random_str(16); return trd_->start(); } srs_error_t SrsLatestVersion::cycle() { srs_error_t err = srs_success; srs_utime_t starttime = srs_update_system_time(); if ((err = query_latest_version()) != srs_success) { srs_warn("query err %s", srs_error_desc(err).c_str()); srs_freep(err); // Ignore any error. } srs_utime_t first_random_wait = 0; srs_random_generate((char*)&first_random_wait, 8); first_random_wait = srs_utime_t(uint64_t((first_random_wait + starttime + getpid())) % (60 * 60)) * SRS_UTIME_SECONDS; // in s. srs_trace("Startup query id=%s, eip=%s, match=%s, stable=%s, wait=%ds, cost=%dms", server_id_.c_str(), srs_get_public_internet_address().c_str(), match_version_.c_str(), stable_version_.c_str(), srsu2msi(first_random_wait)/1000, srsu2msi(srs_update_system_time() - starttime)); srs_usleep(first_random_wait); while (true) { starttime = srs_update_system_time(); if ((err = query_latest_version()) != srs_success) { srs_warn("query err %s", srs_error_desc(err).c_str()); srs_freep(err); // Ignore any error. } srs_trace("Finish query id=%s, eip=%s, match=%s, stable=%s, cost=%dms", server_id_.c_str(), srs_get_public_internet_address().c_str(), match_version_.c_str(), stable_version_.c_str(), srsu2msi(srs_update_system_time() - starttime)); srs_usleep(3600 * SRS_UTIME_SECONDS); // Every an hour. } return err; } srs_error_t SrsLatestVersion::query_latest_version() { srs_error_t err = srs_success; // Generate uri and parse to object. stringstream ss; ss << "http://api.ossrs.net/service/v1/releases?" << "version=v" << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << "&id=" << server_id_ << "&role=srs" << "&eip=" << srs_get_public_internet_address() << "&ts=" << srsu2ms(srs_get_system_time()); string url = ss.str(); SrsHttpUri uri; if ((err = uri.initialize(url)) != srs_success) { return srs_error_wrap(err, "http: post failed. url=%s", url.c_str()); } // Start HTTP request and read response. SrsHttpClient http; if ((err = http.initialize(uri.get_schema(), uri.get_host(), uri.get_port())) != srs_success) { return err; } // Path with query. string path = uri.get_path(); path += "?"; path += uri.get_query(); ISrsHttpMessage* msg = NULL; if ((err = http.get(path, "", &msg)) != srs_success) { return err; } SrsAutoFree(ISrsHttpMessage, msg); string res; int code = msg->status_code(); if ((err = msg->body_read_all(res)) != srs_success) { return err; } // Check the response code and content. if (code != SRS_CONSTS_HTTP_OK) { return srs_error_new(ERROR_HTTP_STATUS_INVALID, "invalid response status=%d", code); } if (res.empty()) { return srs_error_new(ERROR_HTTP_DATA_INVALID, "invalid empty response"); } // Response in json object. SrsJsonAny* jres = SrsJsonAny::loads((char*)res.c_str()); if (!jres || !jres->is_object()) { return srs_error_new(ERROR_HTTP_DATA_INVALID, "invalid response %s", res.c_str()); } SrsAutoFree(SrsJsonAny, jres); SrsJsonObject* obj = jres->to_object(); SrsJsonAny* prop = NULL; // Parse fields of response. if ((prop = obj->ensure_property_string("match_version")) == NULL) { return srs_error_new(ERROR_RESPONSE_CODE, "no match_version"); } match_version_ = prop->to_str(); if ((prop = obj->ensure_property_string("stable_version")) == NULL) { return srs_error_new(ERROR_RESPONSE_CODE, "no stable_version"); } stable_version_ = prop->to_str(); return err; }