adchpp-docker/src/adchpp/Util.cpp

366 lines
7.9 KiB
C++

/*
* Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "adchpp.h"
#include <random>
#include "Util.h"
#include "FastAlloc.h"
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/utsname.h>
#include <ctype.h>
#endif
#include "TimeUtil.h"
namespace adchpp {
using namespace std;
#ifdef NDEBUG
FastMutex FastAllocBase::mtx;
#endif
#ifndef _WIN32
string Util::appName;
string Util::appPath;
#endif
string Util::emptyString;
wstring Util::emptyStringW;
/**
* Decodes a URL the best it can...
* Default ports:
* http:// -> port 80
* dchub:// -> port 411
*/
void Util::decodeUrl(const string& url, string& aServer, short& aPort, string& aFile) {
// First, check for a protocol: xxxx://
string::size_type i = 0, j, k;
aServer.clear();
aFile.clear();
if( (j=url.find("://", i)) != string::npos) {
// Protocol found
string protocol = url.substr(0, j);
i = j + 3;
if(protocol == "http") {
aPort = 80;
} else if(protocol == "dchub") {
aPort = 411;
}
}
if( (j=url.find('/', i)) != string::npos) {
// We have a filename...
aFile = url.substr(j);
}
if( (k=url.find(':', i)) != string::npos) {
// Port
if(k < j)
aPort = (short)Util::toInt(url.substr(k+1, j-k-1));
} else {
k = j;
}
// Only the server should be left now...
aServer = url.substr(i, k-i);
}
void Util::tokenize(StringList& lst, const string& str, char sep, string::size_type j) {
string::size_type i = 0;
while( (i=str.find_first_of(sep, j)) != string::npos ) {
lst.push_back(str.substr(j, i-j));
j = i + 1;
}
if(j <= str.size())
lst.push_back(str.substr(j, str.size()-j));
}
#ifdef _WIN32
string Util::getAppPath() {
string tmp = getAppName();
string::size_type i = tmp.rfind('\\');
if(i != string::npos)
tmp.erase(i+1);
return tmp;
}
string Util::getAppName() {
string tmp(MAX_PATH + 1, '\0');
tmp.resize(::GetModuleFileNameA(NULL, &tmp[0], MAX_PATH));
return tmp;
}
#else // WIN32
void Util::setApp(const string& app) {
string::size_type i = app.rfind('/');
if(i != string::npos) {
appPath = app.substr(0, i+1);
appName = app;
}
}
string Util::getAppPath() {
return appPath;
}
string Util::getAppName() {
return appName;
}
#endif // WIN32
string Util::getLocalIp() {
string tmp;
char buf[256];
gethostname(buf, 255);
hostent* he = gethostbyname(buf);
if(he == NULL || he->h_addr_list[0] == 0)
return Util::emptyString;
sockaddr_in dest;
int i = 0;
// We take the first ip as default, but if we can find a better one, use it instead...
memcpy(&(dest.sin_addr), he->h_addr_list[i++], he->h_length);
tmp = inet_ntoa(dest.sin_addr);
if( strncmp(tmp.c_str(), "192", 3) == 0 ||
strncmp(tmp.c_str(), "169", 3) == 0 ||
strncmp(tmp.c_str(), "127", 3) == 0 ||
strncmp(tmp.c_str(), "10", 2) == 0 ) {
while(he->h_addr_list[i]) {
memcpy(&(dest.sin_addr), he->h_addr_list[i], he->h_length);
string tmp2 = inet_ntoa(dest.sin_addr);
if( strncmp(tmp2.c_str(), "192", 3) != 0 &&
strncmp(tmp2.c_str(), "169", 3) != 0 &&
strncmp(tmp2.c_str(), "127", 3) != 0 &&
strncmp(tmp2.c_str(), "10", 2) != 0) {
tmp = tmp2;
}
i++;
}
}
return tmp;
}
string Util::formatBytes(int64_t aBytes) {
char buf[64];
if(aBytes < 1024) {
sprintf(buf, "%d B", (int)(aBytes&0xffffffff));
} else if(aBytes < 1024*1024) {
sprintf(buf, "%.02f KiB", (double)aBytes/(1024.0));
} else if(aBytes < 1024*1024*1024) {
sprintf(buf, "%.02f MiB", (double)aBytes/(1024.0*1024.0));
} else if(aBytes < (int64_t)1024*1024*1024*1024) {
sprintf(buf, "%.02f GiB", (double)aBytes/(1024.0*1024.0*1024.0));
} else {
sprintf(buf, "%.02f TiB", (double)aBytes/(1024.0*1024.0*1024.0*1024.0));
}
return buf;
}
string Util::getShortTimeString() {
char buf[8];
time_t _tt;
std::time(&_tt);
tm* _tm = localtime(&_tt);
strftime(buf, 8, "%H:%M", _tm);
return buf;
}
string Util::getTimeString() {
char buf[64];
time_t _tt;
std::time(&_tt);
tm* _tm = localtime(&_tt);
if(_tm == NULL) {
strcpy(buf, "xx:xx:xx");
} else {
strftime(buf, 64, "%X", _tm);
}
return buf;
}
string Util::formatTime(const string& msg, time_t t /* = time(NULL) */) {
size_t bufsize = msg.size() + 64;
char* buf = new char[bufsize];
while(!strftime(buf, bufsize-1, msg.c_str(), localtime(&t))) {
delete buf;
bufsize+=64;
buf = new char[bufsize];
}
string result = buf;
delete[] buf;
return result;
}
string Util::translateError(int aError) {
#ifdef _WIN32
LPVOID lpMsgBuf;
::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
aError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
#ifdef _UNICODE
string tmp = Util::toAcp((LPCTSTR)lpMsgBuf);
#else
string tmp = (LPCTSTR)lpMsgBuf;
#endif
// Free the buffer.
LocalFree( lpMsgBuf );
#else // WIN32
string tmp = strerror(aError);
#endif // WIN32
string::size_type i = 0;
while( (i = tmp.find_first_of("\r\n", i)) != string::npos) {
tmp.erase(i, 1);
}
return tmp;
}
string Util::getOsVersion() {
#ifdef _WIN32
string os;
OSVERSIONINFOEX ver;
memset(&ver, 0, sizeof(OSVERSIONINFOEX));
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if(!GetVersionEx((OSVERSIONINFO*)&ver)) {
ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if(!GetVersionEx((OSVERSIONINFO*)&ver)) {
os = "Windows (version unknown)";
}
}
if(os.empty()) {
if(ver.dwPlatformId != VER_PLATFORM_WIN32_NT) {
os = "Win9x/ME/Junk";
} else if(ver.dwMajorVersion == 4) {
os = "WinNT4";
} else if(ver.dwMajorVersion == 5) {
if(ver.dwMinorVersion == 0) {
os = "Win2000";
} else if(ver.dwMinorVersion == 1) {
os = "WinXP";
} else if(ver.dwMinorVersion == 2) {
os = "Win2003";
} else {
os = "WinUnknown";
}
if(ver.wProductType == VER_NT_WORKSTATION)
os += " Pro";
else if(ver.wProductType == VER_NT_SERVER)
os += " Server";
else if(ver.wProductType == VER_NT_DOMAIN_CONTROLLER)
os += " DC";
}
if(ver.wServicePackMajor > 0) {
os += " SP" + Util::toString(ver.wServicePackMajor);
}
}
return os;
#else // WIN32
utsname n;
if(uname(&n) != 0) {
return "unix (unknown version)";
}
return string(n.sysname) + " " + string(n.release) + " (" + string(n.machine) + ")";
#endif // WIN32
}
#ifdef __MINGW32__
// creating a random_device throws an exception in MinGW with GCC 4.6; simpler alternative...
uint32_t Util::rand() {
static bool init = false;
if(!init) {
::srand(::time(0));
init = true;
}
return ::rand();
}
#else
uint32_t Util::rand() {
static std::random_device rd;
static std::default_random_engine dre(rd());
return dre();
}
#endif
bool Util::isPrivateIp(std::string const& ip) {
struct in_addr addr;
addr.s_addr = inet_addr(ip.c_str());
if (addr.s_addr != INADDR_NONE) {
unsigned long haddr = ntohl(addr.s_addr);
return ((haddr & 0xff000000) == 0x0a000000 || // 10.0.0.0/8
(haddr & 0xff000000) == 0x7f000000 || // 127.0.0.0/8
(haddr & 0xfff00000) == 0xac100000 || // 172.16.0.0/12
(haddr & 0xffff0000) == 0xc0a80000); // 192.168.0.0/16
}
return false;
}
bool Util::validateCharset(std::string const& field, int p) {
for(string::size_type i = 0; i < field.length(); ++i) {
if((uint8_t) field[i] < p) {
return false;
}
}
return true;
}
}