// // ZoneMinder Monitor::RTSP2WebManager Class Implementation, $Date$, $Revision$ // Copyright (C) 2022 Jonathan Bennett // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. // #include "zm_crypt.h" #include "zm_monitor.h" #include "zm_server.h" #include "zm_time.h" #include #include std::string remove_newlines(std::string input); std::string escape_json_string(std::string input); Monitor::RTSP2WebManager::RTSP2WebManager(Monitor *parent_) : parent(parent_), RTSP2Web_Healthy(false) { Use_RTSP_Restream = false; if ((config.rtsp2web_path != nullptr) && (config.rtsp2web_path[0] != '\0')) { RTSP2Web_endpoint = config.rtsp2web_path; //remove the trailing slash if present if (RTSP2Web_endpoint.back() == '/') RTSP2Web_endpoint.pop_back(); } else { RTSP2Web_endpoint = "demo:demo@127.0.0.1:8083"; } rtsp_path = parent->path; if (!parent->user.empty()) { rtsp_username = escape_json_string(parent->user); rtsp_password = escape_json_string(parent->pass); if (rtsp_path.find("rtsp://") == 0) { rtsp_path = "rtsp://" + rtsp_username + ":" + rtsp_password + "@" + rtsp_path.substr(7, std::string::npos); } else { rtsp_path = "rtsp://" + rtsp_username + ":" + rtsp_password + "@" + rtsp_path; } } Debug(1, "Monitor %u rtsp url is %s", parent->id, rtsp_path.c_str()); } Monitor::RTSP2WebManager::~RTSP2WebManager() { remove_from_RTSP2Web(); } int Monitor::RTSP2WebManager::check_RTSP2Web() { curl = curl_easy_init(); if (!curl) return -1; //Assemble our actual request std::string response; std::string endpoint = RTSP2Web_endpoint+"/stream/"+std::to_string(parent->id)+"/info"; curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); CURLcode res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res != CURLE_OK) { Warning("Attempted to send to %s and got %s", endpoint.c_str(), curl_easy_strerror(res)); return -1; } Debug(1, "Queried for stream status: %s", remove_newlines(response).c_str()); if (response.find("\"status\": 0") != std::string::npos) { if (response.find("stream not found") != std::string::npos) { Warning("Mountpoint Missing"); return 0; } else { Warning("unknown RTSP2Web error"); return 0; } } return 1; } int Monitor::RTSP2WebManager::add_to_RTSP2Web() { Debug(1, "Adding stream to RTSP2Web"); curl = curl_easy_init(); if (!curl) { Error("Failed to init curl"); return -1; } std::string endpoint = RTSP2Web_endpoint+"/stream/"+std::to_string(parent->id)+"/add"; //Assemble our actual request std::string postData = "{\"name\" : \""; postData += std::string(parent->Name()); postData += "\", \"channels\" : { \"0\" : {"; postData += "\"name\" : \"ch1\", \"url\" : \""; postData += rtsp_path; postData += "\", \"on_demand\": true, \"debug\": false, \"status\": 0}}}"; Debug(1, "Sending %s to %s", postData.c_str(), endpoint.c_str()); CURLcode res; std::string response; curl_easy_setopt(curl, CURLOPT_URL, endpoint.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str()); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res != CURLE_OK) { Error("Failed to curl_easy_perform adding rtsp stream %s", curl_easy_strerror(res)); return -1; } Debug(1, "Adding stream response: %s", remove_newlines(response).c_str()); //scan for missing session or handle id "No such session" "no such handle" if (response.find("\"status\": 1") == std::string::npos) { Warning("RTSP2Web failed adding stream, response: %s", response.c_str()); return -2; } Debug(1,"Added stream to RTSP2Web: %s", response.c_str()); return 0; } int Monitor::RTSP2WebManager::remove_from_RTSP2Web() { curl = curl_easy_init(); if (!curl) return -1; std::string endpoint = RTSP2Web_endpoint+"/stream/"+std::to_string(parent->id)+"/delete"; std::string response; curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { Warning("Libcurl attempted %s got %s", endpoint.c_str(), curl_easy_strerror(res)); } else { Debug(1, "Removed stream from RTSP2Web: %s", remove_newlines(response).c_str()); } curl_easy_cleanup(curl); return 0; } size_t Monitor::RTSP2WebManager::WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } std::string remove_newlines( std::string str ) { while (!str.empty() && str.find("\n") != std::string::npos) str.erase(std::remove(str.begin(), str.end(), '\n'), str.cend()); return str; } /* std::string escape_json_string( std::string input ) { std::string tmp; tmp = regex_replace(input, std::regex("\n"), "\\n"); tmp = regex_replace(tmp, std::regex("\b"), "\\b"); tmp = regex_replace(tmp, std::regex("\f"), "\\f"); tmp = regex_replace(tmp, std::regex("\r"), "\\r"); tmp = regex_replace(tmp, std::regex("\t"), "\\t"); tmp = regex_replace(tmp, std::regex("\""), "\\\""); tmp = regex_replace(tmp, std::regex("[\\\\]"), "\\\\"); return tmp; } */