📄 network.cc
字号:
#include <algorithm>#include <cassert>#include <cfloat>#include <cmath>#include <sstream>#ifdef POSIXextern "C" {#include <sys/socket.h>#include <sys/utsname.h>#include <sys/ioctl.h>#include <net/if.h>#include <unistd.h>#include <errno.h>}#endif // POSIX#ifdef WIN32#include "win32.h"#include <Iphlpapi.h>#endif#include "host.h"#include "logging.h"#include "network.h"#include "socket.h" // this includes something that makes windows happy#include "stringencode.h"#include "time.h"#include "basicdefs.h"namespace {const double kAlpha = 0.5; // weight for data infinitely far in the pastconst double kHalfLife = 2000; // half life of exponential decay (in ms)const double kLog2 = 0.693147180559945309417;const double kLambda = kLog2 / kHalfLife;// assume so-so quality unless data says otherwiseconst double kDefaultQuality = utils_base::QUALITY_FAIR;typedef std::map<std::string,std::string> StrMap;void BuildMap(const StrMap& map, std::string& str) { str.append("{"); bool first = true; for (StrMap::const_iterator i = map.begin(); i != map.end(); ++i) { if (!first) str.append(","); str.append(i->first); str.append("="); str.append(i->second); first = false; } str.append("}");}void ParseCheck(std::istringstream& ist, char ch) { if (ist.get() != ch) LOG(LERROR) << "Expecting '" << ch << "'";}std::string ParseString(std::istringstream& ist) { std::string str; int count = 0; while (ist) { char ch = ist.peek(); if ((count == 0) && ((ch == '=') || (ch == ',') || (ch == '}'))) { break; } else if (ch == '{') { count += 1; } else if (ch == '}') { count -= 1; if (count < 0) LOG(LERROR) << "mismatched '{' and '}'"; } str.append(1, static_cast<char>(ist.get())); } return str;}void ParseMap(const std::string& str, StrMap& map) { if (str.size() == 0) return; std::istringstream ist(str); ParseCheck(ist, '{'); for (;;) { std::string key = ParseString(ist); ParseCheck(ist, '='); std::string val = ParseString(ist); map[key] = val; if (ist.peek() == ',') ist.get(); else break; } ParseCheck(ist, '}'); if (ist.rdbuf()->in_avail() != 0) LOG(LERROR) << "Unexpected characters at end";}#if 0const std::string TEST_MAP0_IN = "";const std::string TEST_MAP0_OUT = "{}";const std::string TEST_MAP1 = "{a=12345}";const std::string TEST_MAP2 = "{a=12345,b=67890}";const std::string TEST_MAP3 = "{a=12345,b=67890,c=13579}";const std::string TEST_MAP4 = "{a={d=12345,e=67890}}";const std::string TEST_MAP5 = "{a={d=12345,e=67890},b=67890}";const std::string TEST_MAP6 = "{a=12345,b={d=12345,e=67890}}";const std::string TEST_MAP7 = "{a=12345,b={d=12345,e=67890},c=13579}";class MyTest {public: MyTest() { test(TEST_MAP0_IN, TEST_MAP0_OUT); test(TEST_MAP1, TEST_MAP1); test(TEST_MAP2, TEST_MAP2); test(TEST_MAP3, TEST_MAP3); test(TEST_MAP4, TEST_MAP4); test(TEST_MAP5, TEST_MAP5); test(TEST_MAP6, TEST_MAP6); test(TEST_MAP7, TEST_MAP7); } void test(const std::string& input, const std::string& exp_output) { StrMap map; ParseMap(input, map); std::string output; BuildMap(map, output); LOG(INFO) << " ******** " << (output == exp_output); }};static MyTest myTest;#endif} // namespacenamespace utils_base {#ifdef POSIXvoid NetworkManager::CreateNetworks(std::vector<Network*>& networks) { int fd; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { PLOG(LERROR, errno) << "socket"; return; } struct ifconf ifc; ifc.ifc_len = 64 * sizeof(struct ifreq); ifc.ifc_buf = new char[ifc.ifc_len]; if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { PLOG(LERROR, errno) << "ioctl"; return; } assert(ifc.ifc_len < static_cast<int>(64 * sizeof(struct ifreq))); struct ifreq* ptr = reinterpret_cast<struct ifreq*>(ifc.ifc_buf); struct ifreq* end = reinterpret_cast<struct ifreq*>(ifc.ifc_buf + ifc.ifc_len); while (ptr < end) { if (strcmp(ptr->ifr_name, "lo")) { // Ignore the loopback device struct sockaddr_in* inaddr = reinterpret_cast<struct sockaddr_in*>(&ptr->ifr_ifru.ifru_addr); if (inaddr->sin_family == AF_INET) { uint32 ip = ntohl(inaddr->sin_addr.s_addr); networks.push_back(new Network(std::string(ptr->ifr_name), ip)); } }#ifdef _SIZEOF_ADDR_IFREQ ptr = reinterpret_cast<struct ifreq*>( reinterpret_cast<char*>(ptr) + _SIZEOF_ADDR_IFREQ(*ptr));#else ptr++;#endif } delete [] ifc.ifc_buf; close(fd);}#endif#ifdef WIN32void NetworkManager::CreateNetworks(std::vector<Network*>& networks) { IP_ADAPTER_INFO info_temp; ULONG len = 0; if (GetAdaptersInfo(&info_temp, &len) != ERROR_BUFFER_OVERFLOW) return; IP_ADAPTER_INFO *infos = new IP_ADAPTER_INFO[len]; if (GetAdaptersInfo(infos, &len) != NO_ERROR) return; int count = 0; for (IP_ADAPTER_INFO *info = infos; info != NULL; info = info->Next) { if (info->Type == MIB_IF_TYPE_LOOPBACK) continue; if (strcmp(info->IpAddressList.IpAddress.String, "0.0.0.0") == 0) continue; // In production, don't transmit the network name because of // privacy concerns. Transmit a number instead. std::string name;#if defined(PRODUCTION) std::ostringstream ost; ost << count; name = ost.str(); count++;#else name = info->Description;#endif networks.push_back(new Network(name, SocketAddress::StringToIP(info->IpAddressList.IpAddress.String))); } delete infos;}#endifvoid NetworkManager::GetNetworks(std::vector<Network*>& result) { std::vector<Network*> list; CreateNetworks(list); for (uint32 i = 0; i < list.size(); ++i) { NetworkMap::iterator iter = networks_.find(list[i]->name()); Network* network; if (iter == networks_.end()) { network = list[i]; } else { network = iter->second; network->set_ip(list[i]->ip()); delete list[i]; } networks_[network->name()] = network; result.push_back(network); }}std::string NetworkManager::GetState() { StrMap map; for (NetworkMap::iterator i = networks_.begin(); i != networks_.end(); ++i) map[i->first] = i->second->GetState(); std::string str; BuildMap(map, str); return str;}void NetworkManager::SetState(std::string str) { StrMap map; ParseMap(str, map); for (StrMap::iterator i = map.begin(); i != map.end(); ++i) { std::string name = i->first; std::string state = i->second; Network* network = new Network(name, 0); network->SetState(state); networks_[name] = network; }}Network::Network(const std::string& name, uint32 ip) : name_(name), ip_(ip), uniform_numerator_(0), uniform_denominator_(0), exponential_numerator_(0), exponential_denominator_(0), quality_(kDefaultQuality) { last_data_time_ = Time(); // TODO: seed the historical data with one data point based on the link speed // metric from XP (4.0 if < 50, 3.0 otherwise).}void Network::StartSession(NetworkSession* session) { assert(std::find(sessions_.begin(), sessions_.end(), session) == sessions_.end()); sessions_.push_back(session);}void Network::StopSession(NetworkSession* session) { SessionList::iterator iter = std::find(sessions_.begin(), sessions_.end(), session); if (iter != sessions_.end()) sessions_.erase(iter);}void Network::EstimateQuality() { uint32 now = Time(); // Add new data points for the current time. for (uint32 i = 0; i < sessions_.size(); ++i) { if (sessions_[i]->HasQuality()) AddDataPoint(now, sessions_[i]->GetCurrentQuality()); } // Construct the weighted average using both uniform and exponential weights. double exp_shift = exp(-kLambda * (now - last_data_time_)); double numerator = uniform_numerator_ + exp_shift * exponential_numerator_; double denominator = uniform_denominator_ + exp_shift * exponential_denominator_; if (denominator < DBL_EPSILON) quality_ = kDefaultQuality; else quality_ = numerator / denominator;}std::string Network::ToString() const { std::stringstream ss; // Print out the first space-terminated token of the network name, plus // the IP address. ss << "Net[" << name_.substr(0, name_.find(' ')) << ":" << SocketAddress::IPToString(ip_) << "]"; return ss.str();}void Network::AddDataPoint(uint32 time, double quality) { uniform_numerator_ += kAlpha * quality; uniform_denominator_ += kAlpha; double exp_shift = exp(-kLambda * (time - last_data_time_)); exponential_numerator_ = (1 - kAlpha) * quality + exp_shift * exponential_numerator_; exponential_denominator_ = (1 - kAlpha) + exp_shift * exponential_denominator_; last_data_time_ = time;}std::string Network::GetState() { StrMap map; map["lt"] = utils_base::ToString<uint32>(last_data_time_); map["un"] = utils_base::ToString<double>(uniform_numerator_); map["ud"] = utils_base::ToString<double>(uniform_denominator_); map["en"] = utils_base::ToString<double>(exponential_numerator_); map["ed"] = utils_base::ToString<double>(exponential_denominator_); std::string str; BuildMap(map, str); return str;}void Network::SetState(std::string str) { StrMap map; ParseMap(str, map); last_data_time_ = FromString<uint32>(map["lt"]); uniform_numerator_ = FromString<double>(map["un"]); uniform_denominator_ = FromString<double>(map["ud"]); exponential_numerator_ = FromString<double>(map["en"]); exponential_denominator_ = FromString<double>(map["ed"]);}} // namespace utils_base
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -