#include "controller_limits.h" #include "controller_statistics.h" #include "controller_storage.h" #include #include #include #include namespace Controller{ void checkStreamLimits(std::string streamName, long long currentKbps, long long connectedUsers){ if (!Storage["streams"].isMember(streamName)){return;} if (!Storage["streams"][streamName].isMember("limits")){return;} if (!Storage["streams"][streamName]["limits"]){return;} Storage["streams"][streamName].removeMember("hardlimit_active"); if (Storage["streams"][streamName]["online"].asInt() != 1){ jsonForEach(Storage["streams"][streamName]["limits"], limitIt){ if ((*limitIt).isMember("triggered")){ if ((*limitIt)["type"].asString() == "soft"){ Log("SLIM", "Softlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " for stream " + streamName + " reset - stream unavailable."); }else{ Log("HLIM", "Hardlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " for stream " + streamName + " reset - stream unavailable."); } (*limitIt).removeMember("triggered"); } } return; } // run over all limits. jsonForEach(Storage["streams"][streamName]["limits"], limitIt){ bool triggerLimit = false; if ((*limitIt)["name"].asString() == "users" && connectedUsers >= (*limitIt)["value"].asInt()){ triggerLimit = true; } if ((*limitIt)["name"].asString() == "kbps_max" && currentKbps >= (*limitIt)["value"].asInt()){ triggerLimit = true; } if (triggerLimit){ if ((*limitIt)["type"].asString() == "hard"){ Storage["streams"][streamName]["hardlimit_active"] = true; } if ((*limitIt).isMember("triggered")){continue;} if ((*limitIt)["type"].asString() == "soft"){ Log("SLIM", "Softlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " for stream " + streamName + " triggered."); }else{ Log("HLIM", "Hardlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " for stream " + streamName + " triggered."); } (*limitIt)["triggered"] = true; }else{ if (!(*limitIt).isMember("triggered")){continue;} if ((*limitIt)["type"].asString() == "soft"){ Log("SLIM", "Softlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " for stream " + streamName + " reset."); }else{ Log("HLIM", "Hardlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " for stream " + streamName + " reset."); } (*limitIt).removeMember("triggered"); } } } void checkServerLimits(){ int currentKbps = 0; int connectedUsers = 0; std::map strmUsers; std::map strmBandw; /* if (curConns.size()){ for (std::map::iterator it = curConns.begin(); it != curConns.end(); it++){ if (it->second.log.size() < 2){continue;} std::map::reverse_iterator statRef = it->second.log.rbegin(); std::map::reverse_iterator prevRef = --(it->second.log.rbegin()); unsigned int diff = statRef->first - prevRef->first; strmUsers[it->second.streamName]++; connectedUsers++; strmBandw[it->second.streamName] += (((statRef->second.down - prevRef->second.down) + (statRef->second.up - prevRef->second.up)) / diff); currentKbps += (((statRef->second.down - prevRef->second.down) + (statRef->second.up - prevRef->second.up)) / diff); } } */ // check stream limits if (Storage["streams"].size()){ jsonForEach(Storage["streams"], strmIt){ checkStreamLimits(strmIt.key(), strmBandw[strmIt.key()], strmUsers[strmIt.key()]); } } Storage["config"].removeMember("hardlimit_active"); if (!Storage["config"]["limits"].size()){return;} if (!Storage["streams"].size()){return;} jsonForEach(Storage["config"]["limits"], limitIt){ bool triggerLimit = false; if ((*limitIt)["name"].asString() == "users" && connectedUsers >= (*limitIt)["value"].asInt()){ triggerLimit = true; } if ((*limitIt)["name"].asString() == "kbps_max" && currentKbps >= (*limitIt)["value"].asInt()){ triggerLimit = true; } if (triggerLimit){ if ((*limitIt)["type"].asString() == "hard"){ Storage["config"]["hardlimit_active"] = true; } if ((*limitIt).isMember("triggered")){continue;} if ((*limitIt)["type"].asString() == "soft"){ Log("SLIM", "Serverwide softlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " triggered."); }else{ Log("HLIM", "Serverwide hardlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " triggered."); } (*limitIt)["triggered"] = true; }else{ if (!(*limitIt).isMember("triggered")){continue;} if ((*limitIt)["type"].asString() == "soft"){ Log("SLIM", "Serverwide softlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " reset."); }else{ Log("HLIM", "Serverwide hardlimit " + (*limitIt)["name"].asString() + " <= " + (*limitIt)["value"].asString() + " reset."); } (*limitIt).removeMember("triggered"); } } } bool onList(std::string ip, std::string list){ if (list == ""){return false;} std::string entry; std::string lowerIpv6; // lower-case std::string upperIpv6; // full-caps do{ entry = list.substr(0, list.find(" ")); // make sure we have a single entry lowerIpv6 = "::ffff:" + entry; upperIpv6 = "::FFFF:" + entry; if (entry == ip || lowerIpv6 == ip || upperIpv6 == ip){return true;} long long unsigned int starPos = entry.find("*"); if (starPos == std::string::npos){ if (ip == entry){return true;} }else{ if (starPos == 0){// beginning of the filter if (ip.substr(ip.length() - entry.size() - 1) == entry.substr(1)){return true;} }else{ if (starPos == entry.size() - 1){// end of the filter if (ip.find(entry.substr(0, entry.size() - 1)) == 0){return true;} if (ip.find(entry.substr(0, lowerIpv6.size() - 1)) == 0){return true;} if (ip.find(entry.substr(0, upperIpv6.size() - 1)) == 0){return true;} }else{ Log("CONF", "Invalid list entry detected: " + entry); } } } list.erase(0, entry.size() + 1); }while (list != ""); return false; } std::string hostLookup(std::string ip){ struct sockaddr_in6 sa; char hostName[1024]; char service[20]; if (inet_pton(AF_INET6, ip.c_str(), &(sa.sin6_addr)) != 1){return "\n";} sa.sin6_family = AF_INET6; sa.sin6_port = 0; sa.sin6_flowinfo = 0; sa.sin6_scope_id = 0; int tmpRet = getnameinfo((struct sockaddr *)&sa, sizeof sa, hostName, sizeof hostName, service, sizeof service, NI_NAMEREQD); if (tmpRet == 0){return hostName;} return ""; } bool isBlacklisted(std::string host, std::string streamName, int timeConnected){ std::string myHostName = hostLookup(host); if (myHostName == "\n"){return false;} bool hasWhitelist = false; bool hostOnWhitelist = false; if (Storage["streams"].isMember(streamName)){ if (Storage["streams"][streamName].isMember("limits") && Storage["streams"][streamName]["limits"].size()){ jsonForEach(Storage["streams"][streamName]["limits"], limitIt){ if ((*limitIt)["name"].asString() == "host"){ if ((*limitIt)["value"].asString()[0] == '+'){ if (!onList(host, (*limitIt)["value"].asString().substr(1))){ if (myHostName == ""){ if (timeConnected > Storage["config"]["limit_timeout"].asInt()){return true;} }else{ if (!onList(myHostName, (*limitIt)["value"].asString().substr(1))){ if ((*limitIt)["type"].asString() == "hard"){ Log("HLIM", "Host " + host + " not whitelisted for stream " + streamName); return true; }else{ Log("SLIM", "Host " + host + " not whitelisted for stream " + streamName); } } } } }else{ if ((*limitIt)["value"].asString()[0] == '-'){ if (onList(host, (*limitIt)["value"].asString().substr(1))){ if ((*limitIt)["type"].asString() == "hard"){ Log("HLIM", "Host " + host + " blacklisted for stream " + streamName); return true; }else{ Log("SLIM", "Host " + host + " blacklisted for stream " + streamName); } } if (myHostName != "" && onList(myHostName, (*limitIt)["value"].asString().substr(1))){ if ((*limitIt)["type"].asString() == "hard"){ Log("HLIM", "Host " + myHostName + " blacklisted for stream " + streamName); return true; }else{ Log("SLIM", "Host " + myHostName + " blacklisted for stream " + streamName); } } } } } } } } if (Storage["config"]["limits"].size()){ jsonForEach(Storage["config"]["limits"], limitIt){ if ((*limitIt)["name"].asString() == "host"){ if ((*limitIt)["value"].asString()[0] == '+'){ if (!onList(host, (*limitIt)["value"].asString().substr(1))){ if (myHostName == ""){ if (timeConnected > Storage["config"]["limit_timeout"].asInt()){return true;} }else{ if (!onList(myHostName, (*limitIt)["value"].asString().substr(1))){ if ((*limitIt)["type"].asString() == "hard"){ Log("HLIM", "Host " + host + " not whitelisted for stream " + streamName); return true; }else{ Log("SLIM", "Host " + host + " not whitelisted for stream " + streamName); } } } } }else{ if ((*limitIt)["value"].asString()[0] == '-'){ if (onList(host, (*limitIt)["value"].asString().substr(1))){ if ((*limitIt)["type"].asString() == "hard"){ Log("HLIM", "Host " + host + " blacklisted for stream " + streamName); return true; }else{ Log("SLIM", "Host " + host + " blacklisted for stream " + streamName); } } if (myHostName != "" && onList(myHostName, (*limitIt)["value"].asString().substr(1))){ if ((*limitIt)["type"].asString() == "hard"){ Log("HLIM", "Host " + myHostName + " blacklisted for stream " + streamName); return true; }else{ Log("SLIM", "Host " + myHostName + " blacklisted for stream " + streamName); } } } } } } } if (hasWhitelist){ if (hostOnWhitelist || myHostName == ""){ return false; }else{ return true; } } return false; } }// namespace Controller