From 79e3f669f0a8a4c63cbdca2b8d824db59cf3bc61 Mon Sep 17 00:00:00 2001 From: EinMByte Date: Sun, 19 Jul 2015 17:52:28 +0200 Subject: [PATCH] Cleanup util, add documentation. --- util.cpp | 598 ++++++++++++++++++++++++++----------------------------- util.h | 93 ++++++++- 2 files changed, 368 insertions(+), 323 deletions(-) diff --git a/util.cpp b/util.cpp index 6257da9f..d8735ccf 100644 --- a/util.cpp +++ b/util.cpp @@ -60,50 +60,43 @@ http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */ } #endif -namespace i2p -{ - namespace util - { +namespace i2p { +namespace util { - namespace config - { - std::map mapArgs; - std::map > mapMultiArgs; +namespace config { + std::map mapArgs; + std::map > mapMultiArgs; - void OptionParser(int argc, const char* const argv[]) + void OptionParser(int argc, const char* const argv[]) { mapArgs.clear(); mapMultiArgs.clear(); - for (int i = 1; i < argc; i++) - { + for(int i = 1; i < argc; ++i) { std::string strKey (argv[i]); std::string strValue; size_t has_data = strKey.find('='); - if (has_data != std::string::npos) - { + if(has_data != std::string::npos) { strValue = strKey.substr(has_data+1); strKey = strKey.substr(0, has_data); } #ifdef WIN32 boost::to_lower(strKey); - if (boost::algorithm::starts_with(strKey, "/")) + if(boost::algorithm::starts_with(strKey, "/")) strKey = "-" + strKey.substr(1); #endif - if (strKey[0] != '-') + if(strKey[0] != '-') break; mapArgs[strKey] = strValue; mapMultiArgs[strKey].push_back(strValue); } - BOOST_FOREACH(PAIRTYPE(const std::string,std::string)& entry, mapArgs) - { + for(auto& entry : mapArgs) { std::string name = entry.first; // interpret --foo as -foo (as long as both are not set) - if (name.find("--") == 0) - { + if (name.find("--") == 0) { std::string singleDash(name.begin()+1, name.end()); if (mapArgs.count(singleDash) == 0) mapArgs[singleDash] = entry.second; @@ -114,41 +107,42 @@ namespace i2p const char* GetCharArg(const std::string& strArg, const std::string& nDefault) { - if (mapArgs.count(strArg)) + if(mapArgs.count(strArg)) return mapArgs[strArg].c_str(); return nDefault.c_str(); } std::string GetArg(const std::string& strArg, const std::string& strDefault) { - if (mapArgs.count(strArg)) + if(mapArgs.count(strArg)) return mapArgs[strArg]; return strDefault; } int GetArg(const std::string& strArg, int nDefault) { - if (mapArgs.count(strArg)) - return atoi(mapArgs[strArg].c_str()); + if(mapArgs.count(strArg)) + return stoi(mapArgs[strArg]); return nDefault; } + } namespace filesystem { - std::string appName ("i2pd"); + std::string appName("i2pd"); - void SetAppName (const std::string& name) + void SetAppName(const std::string& name) { appName = name; } - std::string GetAppName () + std::string GetAppName() { return appName; } - const boost::filesystem::path &GetDataDir() + const boost::filesystem::path& GetDataDir() { static boost::filesystem::path path; @@ -157,81 +151,59 @@ namespace filesystem /*if (i2p::util::config::mapArgs.count("-datadir")) path = boost::filesystem::system_complete(i2p::util::config::mapArgs["-datadir"]); else */ - path = GetDefaultDataDir(); + path = GetDefaultDataDir(); - if (!boost::filesystem::exists( path )) - { + if(!boost::filesystem::exists(path)) { // Create data directory - if (!boost::filesystem::create_directory( path )) - { + if(!boost::filesystem::create_directory(path)) { LogPrint("Failed to create data directory!"); path = ""; return path; } } - if (!boost::filesystem::is_directory(path)) + if(!boost::filesystem::is_directory(path)) path = GetDefaultDataDir(); return path; } - std::string GetFullPath (const std::string& filename) + std::string GetFullPath(const std::string& filename) { - std::string fullPath = GetDataDir ().string (); + std::string fullPath = GetDataDir().string(); #ifndef _WIN32 - fullPath.append ("/"); + fullPath.append("/"); #else - fullPath.append ("\\"); + fullPath.append("\\"); #endif - fullPath.append (filename); + fullPath.append(filename); return fullPath; } boost::filesystem::path GetConfigFile() { boost::filesystem::path pathConfigFile(i2p::util::config::GetArg("-conf", "i2p.conf")); - if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; + if(!pathConfigFile.is_complete()) + pathConfigFile = GetDataDir() / pathConfigFile; return pathConfigFile; } - void ReadConfigFile(std::map& mapSettingsRet, - std::map >& mapMultiSettingsRet) - { - boost::filesystem::ifstream streamConfig(GetConfigFile()); - if (!streamConfig.good()) - return; // No i2pd.conf file is OK - - std::set setOptions; - setOptions.insert("*"); - - for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) - { - // Don't overwrite existing settings so command line settings override i2pd.conf - std::string strKey = std::string("-") + it->string_key; - if (mapSettingsRet.count(strKey) == 0) - { - mapSettingsRet[strKey] = it->value[0]; - } - mapMultiSettingsRet[strKey].push_back(it->value[0]); - } - } - boost::filesystem::path GetDefaultDataDir() { // Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd // Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd // Mac: ~/Library/Application Support/i2pd // Unix: ~/.i2pd or /var/lib/i2pd is system=1 + #ifdef WIN32 // Windows char localAppData[MAX_PATH]; SHGetFolderPath(NULL, CSIDL_APPDATA, 0, NULL, localAppData); return boost::filesystem::path(std::string(localAppData) + "\\" + appName); #else - if (i2p::util::config::GetArg("-service", 0)) // use system folder + if(i2p::util::config::GetArg("-service", 0)) // use system folder return boost::filesystem::path(std::string ("/var/lib/") + appName); boost::filesystem::path pathRet; char* pszHome = getenv("HOME"); - if (pszHome == NULL || strlen(pszHome) == 0) + if(pszHome == NULL || strlen(pszHome) == 0) pathRet = boost::filesystem::path("/"); else pathRet = boost::filesystem::path(pszHome); @@ -247,47 +219,62 @@ namespace filesystem #endif } + void ReadConfigFile(std::map& mapSettingsRet, + std::map >& mapMultiSettingsRet) + { + boost::filesystem::ifstream streamConfig(GetConfigFile()); + if(!streamConfig.good()) + return; // No i2pd.conf file is OK + + std::set setOptions; + setOptions.insert("*"); + + for(boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; + it != end; ++it) { + // Don't overwrite existing settings so command line settings override i2pd.conf + std::string strKey = std::string("-") + it->string_key; + if(mapSettingsRet.count(strKey) == 0) { + mapSettingsRet[strKey] = it->value[0]; + } + mapMultiSettingsRet[strKey].push_back(it->value[0]); + } + } + boost::filesystem::path GetCertificatesDir() { return GetDataDir () / "certificates"; - } + } } namespace http { std::string httpRequest(const std::string& address) { - try - { + try { i2p::util::http::url u(address); boost::asio::ip::tcp::iostream site; // please don't uncomment following line because it's not compatible with boost 1.46 // 1.46 is default boost for Ubuntu 12.04 LTS //site.expires_from_now (boost::posix_time::seconds(30)); - if (u.port_ == 80) + if(u.port_ == 80) site.connect(u.host_, "http"); - else - { + else { std::stringstream ss; ss << u.port_; site.connect(u.host_, ss.str()); } - if (site) - { + if(site) { // User-Agent is needed to get the server list routerInfo files. site << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ - << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; + << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" + << "Connection: close\r\n\r\n"; // read response and extract content - return GetHttpContent (site); - } - else - { - LogPrint ("Can't connect to ", address); + return GetHttpContent(site); + } else { + LogPrint("Can't connect to ", address); return ""; } - } - catch (std::exception& ex) - { - LogPrint ("Failed to download ", address, " : ", ex.what ()); + } catch(const std::exception& ex) { + LogPrint("Failed to download ", address, " : ", ex.what()); return ""; } } @@ -299,59 +286,54 @@ namespace http int status; response >> status; // status std::getline (response, statusMessage); - if (status == 200) // OK - { + if(status == 200) { // OK bool isChunked = false; std::string header; - while (!response.eof () && header != "\r") - { + while(!response.eof() && header != "\r") { std::getline(response, header); auto colon = header.find (':'); - if (colon != std::string::npos) - { + if(colon != std::string::npos) { std::string field = header.substr (0, colon); - if (field == i2p::util::http::TRANSFER_ENCODING) - isChunked = (header.find ("chunked", colon + 1) != std::string::npos); - } + if(field == i2p::util::http::TRANSFER_ENCODING) + isChunked = (header.find("chunked", colon + 1) != std::string::npos); + } } std::stringstream ss; - if (isChunked) - MergeChunkedResponse (response, ss); + if(isChunked) + MergeChunkedResponse(response, ss); else ss << response.rdbuf(); + return ss.str(); - } - else - { - LogPrint ("HTTP response ", status); + } else { + LogPrint("HTTP response ", status); return ""; } } - void MergeChunkedResponse (std::istream& response, std::ostream& merged) + void MergeChunkedResponse(std::istream& response, std::ostream& merged) { - while (!response.eof ()) - { + while(!response.eof()) { std::string hexLen; int len; - std::getline (response, hexLen); - std::istringstream iss (hexLen); + std::getline(response, hexLen); + std::istringstream iss(hexLen); iss >> std::hex >> len; - if (!len) break; - char * buf = new char[len]; - response.read (buf, len); - merged.write (buf, len); + if(!len) + break; + char* buf = new char[len]; + response.read(buf, len); + merged.write(buf, len); delete[] buf; - std::getline (response, hexLen); // read \r\n after chunk + std::getline(response, hexLen); // read \r\n after chunk } } int httpRequestViaI2pProxy(const std::string& address, std::string &content) { content = ""; - try - { + try { boost::asio::ip::tcp::iostream site; // please don't uncomment following line because it's not compatible with boost 1.46 // 1.46 is default boost for Ubuntu 12.04 LTS @@ -360,8 +342,7 @@ namespace http std::stringstream ss; ss << i2p::util::config::GetArg("-httpproxyport", 4446); site.connect("127.0.0.1", ss.str()); } - if (site) - { + if(site) { i2p::util::http::url u(address); std::stringstream ss; ss << "GET " << address << " HTTP/1.0" << std::endl; @@ -378,29 +359,22 @@ namespace http int status; site >> status; // status std::getline(site, statusMessage); - if (status == 200) // OK - { + if(status == 200) { // OK std::string header; - while (std::getline(site, header) && header != "\r"){} + while(std::getline(site, header) && header != "\r"){} std::stringstream ss; ss << site.rdbuf(); content = ss.str(); return status; - } - else - { + } else { LogPrint("HTTP response ", status); return status; } - } - else - { + } else { LogPrint("Can't connect to proxy"); return 408; } - } - catch (std::exception& ex) - { + } catch (std::exception& ex) { LogPrint("Failed to download ", address, " : ", ex.what()); return 408; } @@ -417,47 +391,34 @@ namespace http } - // code for parser tests - //{ - // i2p::util::http::url u_0("http://127.0.0.1:7070/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_1("http://user:password@site.com:8080/asdasd?qqqqqqqqqqqqq"); - // i2p::util::http::url u_2("http://user:password@site.com/asdasd?qqqqqqqqqqqqqq"); - // i2p::util::http::url u_3("http://user:@site.com/asdasd?qqqqqqqqqqqqq"); - // i2p::util::http::url u_4("http://user@site.com/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_5("http://@site.com:800/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_6("http://@site.com:err_port/asdasd?qqqqqqqqqqqq"); - // i2p::util::http::url u_7("http://user:password@site.com:err_port/asdasd?qqqqqqqqqqqq"); - //} void url::parse(const std::string& url_s) { const std::string prot_end("://"); - std::string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); + std::string::const_iterator prot_i = search( + url_s.begin(), url_s.end(), prot_end.begin(), prot_end.end() + ); protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - std::ptr_fun(tolower)); // protocol is icase - if( prot_i == url_s.end() ) + // Make portocol lowercase + transform( + url_s.begin(), prot_i, back_inserter(protocol_), std::ptr_fun(std::tolower) + ); + if(prot_i == url_s.end()) return; advance(prot_i, prot_end.length()); std::string::const_iterator path_i = find(prot_i, url_s.end(), '/'); host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - std::ptr_fun(tolower)); // host is icase + // Make host lowerase + transform(prot_i, path_i, back_inserter(host_), std::ptr_fun(std::tolower)); // parse user/password auto user_pass_i = find(host_.begin(), host_.end(), '@'); - if (user_pass_i != host_.end()) - { + if(user_pass_i != host_.end()) { std::string user_pass = std::string(host_.begin(), user_pass_i); auto pass_i = find(user_pass.begin(), user_pass.end(), ':'); - if (pass_i != user_pass.end()) - { + if (pass_i != user_pass.end()) { user_ = std::string(user_pass.begin(), pass_i); pass_ = std::string(pass_i + 1, user_pass.end()); - } - else + } else user_ = user_pass; host_.assign(user_pass_i + 1, host_.end()); @@ -465,14 +426,12 @@ namespace http // parse port auto port_i = find(host_.begin(), host_.end(), ':'); - if (port_i != host_.end()) - { + if(port_i != host_.end()) { portstr_ = std::string(port_i + 1, host_.end()); host_.assign(host_.begin(), port_i); - try{ + try { port_ = boost::lexical_cast(portstr_); - } - catch (const std::exception& e) { + } catch(const std::exception& e) { port_ = 80; } } @@ -487,209 +446,220 @@ namespace http std::string urlDecode(const std::string& data) { std::string res(data); - for (size_t pos = res.find('%'); pos != std::string::npos; pos = res.find('%',pos+1)) - { - char c = strtol(res.substr(pos+1,2).c_str(), NULL, 16); - res.replace(pos,3,1,c); + for(size_t pos = res.find('%'); pos != std::string::npos; pos = res.find('%', pos + 1)) { + const char c = strtol(res.substr(pos + 1, 2).c_str(), NULL, 16); + res.replace(pos, 3, 1, c); } return res; } } -namespace net -{ - int GetMTU (const boost::asio::ip::address& localAddress) - { +namespace net { + #if defined(__linux__) || defined(__FreeBSD_kernel__) - ifaddrs * ifaddr, * ifa = nullptr; - if (getifaddrs(&ifaddr) == -1) - { - LogPrint (eLogError, "Can't excute getifaddrs"); - return 0; + + int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback) + { + ifaddrs* ifaddr, *ifa = nullptr; + if(getifaddrs(&ifaddr) == -1) { + LogPrint(eLogError, "Can't excute getifaddrs"); + return fallback; } + int family = 0; - // loook for interface matching local address - for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) - { - if (!ifa->ifa_addr) continue; + // look for interface matching local address + for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if(!ifa->ifa_addr) + continue; + family = ifa->ifa_addr->sa_family; - if (family == AF_INET && localAddress.is_v4 ()) - { - sockaddr_in * sa = (sockaddr_in *)ifa->ifa_addr; - if (!memcmp (&sa->sin_addr, localAddress.to_v4 ().to_bytes ().data (), 4)) + if(family == AF_INET && localAddress.is_v4()) { + sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr; + if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4)) break; // address matches - } - else if (family == AF_INET6 && localAddress.is_v6 ()) - { - sockaddr_in6 * sa = (sockaddr_in6 *)ifa->ifa_addr; - if (!memcmp (&sa->sin6_addr, localAddress.to_v6 ().to_bytes ().data (), 16)) + } else if(family == AF_INET6 && localAddress.is_v6()) { + sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr; + if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16)) break; // address matches } } - int mtu = 0; - if (ifa && family) // interface found? - { - int fd = socket (family, SOCK_DGRAM, 0); - if (fd > 0) - { + int mtu = fallback; + if(ifa && family) { // interface found? + int fd = socket(family, SOCK_DGRAM, 0); + if(fd > 0) { ifreq ifr; - strncpy (ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query - if (ioctl (fd, SIOCGIFMTU, &ifr) >= 0) + strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query + if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0) mtu = ifr.ifr_mtu; // MTU else LogPrint (eLogError, "Failed to run ioctl"); - close (fd); - } - else - LogPrint (eLogError, "Failed to create datagram socket"); - } - else - LogPrint (eLogWarning, "Interface for local address", localAddress.to_string (), " not found"); + close(fd); + } else + LogPrint(eLogError, "Failed to create datagram socket"); + } else { + LogPrint( + eLogWarning, "Interface for local address", + localAddress.to_string(), " not found" + ); + } - freeifaddrs (ifaddr); - return mtu; -#elif defined(WIN32) + freeifaddrs(ifaddr); - int result = 576; // fallback MTU + return mtu; + } - DWORD dwRetVal = 0; +#elif defined(WIN32) + int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback) + { ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pAddresses = nullptr; PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; -#ifdef UNICODE - string localAddress_temporary = localAddress.to_string(); - wstring localAddressUniversal (localAddress_temporary.begin(), localAddress_temporary.end()); -#else - std::string localAddressUniversal = localAddress.to_string(); -#endif - if (localAddress.is_v4()) - { - struct sockaddr_in inputAddress; - inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr)); + if(GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) + == ERROR_BUFFER_OVERFLOW) { + FREE(pAddresses); + pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen); + } - if (GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) - == ERROR_BUFFER_OVERFLOW) - { - FREE (pAddresses); - pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC (outBufLen); - } + DWORD dwRetVal = GetAdaptersAddresses( + AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen + ); - dwRetVal = GetAdaptersAddresses (AF_INET, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen); - if (dwRetVal == NO_ERROR) - { - pCurrAddresses = pAddresses; - while (pCurrAddresses) - { - PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; - - pUnicast = pCurrAddresses->FirstUnicastAddress; - if (pUnicast != nullptr) - { - for (int i = 0; pUnicast != nullptr; ++i) - { - LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; - struct sockaddr_in *localInterfaceAddress = (struct sockaddr_in*) lpAddr; - if (localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) - { - result = pAddresses->Mtu; - FREE (pAddresses); - pAddresses = nullptr; - return result; - } - pUnicast = pUnicast->Next; - } - } - else - { - LogPrint (eLogError, "GetMTU() has failed: not a unicast ipv4 address, this is not supported"); - } + if(dwRetVal != NO_ERROR) { + LogPrint( + eLogError, "GetMTU() has failed: enclosed GetAdaptersAddresses() call has failed" + ); + FREE(pAddresses); + return fallback; + } - pCurrAddresses = pCurrAddresses->Next; - } + pCurrAddresses = pAddresses; + while(pCurrAddresses) { + PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; + pUnicast = pCurrAddresses->FirstUnicastAddress; + if(pUnicast == nullptr) { + LogPrint( + eLogError, "GetMTU() has failed: not a unicast ipv4 address, this is not supported" + ); + } + for(int i = 0; pUnicast != nullptr; ++i) { + LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; + sockaddr_in* localInterfaceAddress = (sockaddr_in*) lpAddr; + if(localInterfaceAddress->sin_addr.S_un.S_addr == inputAddress.sin_addr.S_un.S_addr) { + result = pAddresses->Mtu; + FREE(pAddresses); + return result; + } + pUnicast = pUnicast->Next; + } + pCurrAddresses = pCurrAddresses->Next; } - else - { - LogPrint (eLogError, "GetMTU() has failed: enclosed GetAdaptersAddresses() call has failed"); + + LogPrint(eLogError, "GetMTU() error: no usable unicast ipv4 addresses found"); + FREE(pAddresses); + return fallback; + } + + int GetMTUWindowsIpv6(sockaddr_in inputAddress, int fallback) + { + ULONG outBufLen = 0; + PIP_ADAPTER_ADDRESSES pAddresses = nullptr; + PIP_ADAPTER_ADDRESSES pCurrAddresses = nullptr; + PIP_ADAPTER_UNICAST_ADDRESS pUnicast = nullptr; + + if(GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) + == ERROR_BUFFER_OVERFLOW) { + FREE(pAddresses); + pAddresses = (IP_ADAPTER_ADDRESSES*) MALLOC(outBufLen); } + DWORD dwRetVal = GetAdaptersAddresses( + AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen + ); + + if(dwRetVal != NO_ERROR) { + LogPrint( + eLogError, + "GetMTU() has failed: enclosed GetAdaptersAddresses() call has failed" + ); + FREE(pAddresses); + return fallback; } - else if (localAddress.is_v6()) - { - struct sockaddr_in6 inputAddress; - inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr)); - if (GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen) - == ERROR_BUFFER_OVERFLOW) - { - FREE (pAddresses); - pAddresses = (IP_ADAPTER_ADDRESSES *)MALLOC (outBufLen); + bool found_address = false; + pCurrAddresses = pAddresses; + while(pCurrAddresses) { + PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; + pUnicast = pCurrAddresses->FirstUnicastAddress; + if(pUnicast == nullptr) { + LogPrint( + eLogError, + "GetMTU() has failed: not a unicast ipv6 address, this is not supported" + ); } - - dwRetVal = GetAdaptersAddresses (AF_INET6, GAA_FLAG_INCLUDE_PREFIX, nullptr, pAddresses, &outBufLen); - if (dwRetVal == NO_ERROR) - { - bool found_address = false; - pCurrAddresses = pAddresses; - while (pCurrAddresses) - { - PIP_ADAPTER_UNICAST_ADDRESS firstUnicastAddress = pCurrAddresses->FirstUnicastAddress; - - pUnicast = pCurrAddresses->FirstUnicastAddress; - if (pUnicast != nullptr) - { - for (int i = 0; pUnicast != nullptr; ++i) - { - LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; - struct sockaddr_in6 *localInterfaceAddress = (struct sockaddr_in6*) lpAddr; - - for (int j = 0; j != 8; ++j) - { - if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j]) - { - break; - } - else - { - found_address = true; - } - } - if (found_address) - { - result = pAddresses->Mtu; - FREE (pAddresses); - pAddresses = nullptr; - return result; - } - pUnicast = pUnicast->Next; - } + for(int i = 0; pUnicast != nullptr; ++i) { + LPSOCKADDR lpAddr = pUnicast->Address.lpSockaddr; + sockaddr_in6 *localInterfaceAddress = (sockaddr_in6*) lpAddr; + + for (int j = 0; j != 8; ++j) { + if (localInterfaceAddress->sin6_addr.u.Word[j] != inputAddress.sin6_addr.u.Word[j]) { + break; + } else { + found_address = true; } - else - { - LogPrint (eLogError, "GetMTU() has failed: not a unicast ipv6 address, this is not supported"); - } - - pCurrAddresses = pCurrAddresses->Next; + } if (found_address) { + result = pAddresses->Mtu; + FREE(pAddresses); + pAddresses = nullptr; + return result; } - - } - else - { - LogPrint (eLogError, "GetMTU() has failed: enclosed GetAdaptersAddresses() call has failed"); + pUnicast = pUnicast->Next; } + + pCurrAddresses = pCurrAddresses->Next; } - else - { - LogPrint (eLogError, "GetMTU() has failed: address family is not supported"); + + LogPrint(eLogError, "GetMTU() error: no usable unicast ipv6 addresses found"); + FREE(pAddresses); + return fallback; + } + + int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback) + { +#ifdef UNICODE + string localAddress_temporary = localAddress.to_string(); + wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end()); +#else + std::string localAddressUniversal = localAddress.to_string(); +#endif + + if(localAddress.is_v4()) { + sockaddr_in inputAddress; + inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr)); + return GetMTUWindowsIpv4(inputAddress, fallback); + } else if(localAddress.is_v6()) { + sockaddr_in6 inputAddress; + inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr)); + return GetMTUWindowsIpv6(inputAddress, fallback); + } else { + LogPrint(eLogError, "GetMTU() has failed: address family is not supported"); + return result; } - FREE (pAddresses); - pAddresses = nullptr; - LogPrint(eLogError, "GetMTU() error: control flow should never reach this line"); - return result; + } +#endif // WIN32 + + int GetMTU(const boost::asio::ip::address& localAddress) + { + const int fallback = 576; // fallback MTU + +#if defined(__linux__) || defined(__FreeBSD_kernel__) + return GetMTUUnix(localAddress, fallback); +#elif defined(WIN32) + return GetMTUWindows(localAddress, fallback); #endif } } diff --git a/util.h b/util.h index 91bac598..8ae7b863 100644 --- a/util.h +++ b/util.h @@ -18,23 +18,73 @@ namespace util { extern std::map mapArgs; extern std::map > mapMultiArgs; + + /** + * Parses command line arguments, i.e. stores them in config::mapArgs. + */ void OptionParser(int argc, const char* const argv[]); + + /** + * @return a command line argument from config::mapArgs as an int + * @param nDefault the default value to be returned + */ int GetArg(const std::string& strArg, int nDefault); + + /** + * @return a command line argument from config::mapArgs as a std::string + * @param strDefault the default value to be returned + */ std::string GetArg(const std::string& strArg, const std::string& strDefault); + + /** + * @return a command line argument from config::mapArgs as a C-style string + * @param nDefault the default value to be returned + */ const char* GetCharArg(const std::string& strArg, const std::string& nDefault); } namespace filesystem { - void SetAppName (const std::string& name); - std::string GetAppName (); + /** + * Change the application name. + */ + void SetAppName(const std::string& name); - const boost::filesystem::path &GetDataDir(); - std::string GetFullPath (const std::string& filename); - boost::filesystem::path GetDefaultDataDir(); + /** + * @return the application name. + */ + std::string GetAppName(); + + /** + * @return the path of the i2pd directory + */ + const boost::filesystem::path& GetDataDir(); + + /** + * @return the full path of a file within the i2pd directory + */ + std::string GetFullPath(const std::string& filename); + + /** + * @return the path of the configuration file + */ boost::filesystem::path GetConfigFile(); + + /** + * @return the default directory for i2pd data + */ + boost::filesystem::path GetDefaultDataDir(); + + + /** + * Read a configuration file and store its contents in the given maps. + */ void ReadConfigFile(std::map& mapSettingsRet, std::map >& mapMultiSettingsRet); + + /** + * @return the path of the certificates directory + */ boost::filesystem::path GetCertificatesDir(); } @@ -46,10 +96,32 @@ namespace util const char LAST_MODIFIED[] = "Last-Modified"; const char TRANSFER_ENCODING[] = "Transfer-Encoding"; + /** + * Perform an HTTP request. + * @return the result of the request, or an empty string if it fails + */ std::string httpRequest(const std::string& address); - std::string GetHttpContent (std::istream& response); - void MergeChunkedResponse (std::istream& response, std::ostream& merged); - int httpRequestViaI2pProxy(const std::string& address, std::string &content); // return http code + + /** + * @return the content of the given HTTP stream without headers + */ + std::string GetHttpContent(std::istream& response); + + /** + * Merge chunks of a HTTP response into the gien std:ostream object. + */ + void MergeChunkedResponse(std::istream& response, std::ostream& merged); + + /** + * Send an HTTP request through the i2p proxy. + * @return the HTTP status code + */ + int httpRequestViaI2pProxy(const std::string& address, std::string &content); + + + /** + * @return the decoded url + */ std::string urlDecode(const std::string& data); /** @@ -73,7 +145,10 @@ namespace util namespace net { - int GetMTU (const boost::asio::ip::address& localAddress); + /** + * @return the maximum transmission unit, or 576 on failure + */ + int GetMTU(const boost::asio::ip::address& localAddress); } } }