initial commit

This commit is contained in:
2025-08-05 15:53:44 +08:00
commit 09dc02ae52
553 changed files with 137665 additions and 0 deletions

66
third_party/libhv/cpputil/RAII.cpp vendored Executable file
View File

@@ -0,0 +1,66 @@
#include "hplatform.h"
#ifdef OS_WIN
#ifdef ENABLE_WINDUMP
#include <dbghelp.h>
#ifdef _MSC_VER
#pragma comment(lib,"dbghelp.lib")
#endif
static LONG UnhandledException(EXCEPTION_POINTERS *pException) {
char modulefile[256];
GetModuleFileName(NULL, modulefile, sizeof(modulefile));
char* pos = strrchr(modulefile, '\\');
char* modulefilename = pos + 1;
SYSTEMTIME st;
GetLocalTime(&st);
char filename[256];
snprintf(filename, sizeof(filename), "core_%s_%04d%02d%02d_%02d%02d%02d_%03d.dump",
modulefilename,
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
HANDLE hDumpFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
dumpInfo.ExceptionPointers = pException;
dumpInfo.ThreadId = GetCurrentThreadId();
dumpInfo.ClientPointers = TRUE;
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
CloseHandle(hDumpFile);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
#include "hsocket.h"
class WsaRAII {
public:
WsaRAII() {
WSAInit();
#ifdef ENABLE_WINDUMP
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)UnhandledException);
#endif
}
~WsaRAII() {
WSADeinit();
}
};
static WsaRAII s_wsa;
#endif
#ifdef WITH_CURL
#include "curl/curl.h"
#ifdef _MSC_VER
//#pragma comment(lib, "libcurl.a")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wldap32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "crypt32.lib")
#endif
class CurlRAII {
public:
CurlRAII() {
curl_global_init(CURL_GLOBAL_ALL);
}
~CurlRAII() {
curl_global_cleanup();
}
};
static CurlRAII s_curl;
#endif

20
third_party/libhv/cpputil/README.md vendored Executable file
View File

@@ -0,0 +1,20 @@
## 目录结构
```
.
├── hasync.h hv::async实现
├── hdir.h 目录(ls实现)
├── hfile.h 文件类
├── hobjectpool.h 对象池
├── hpath.h 路径操作
├── hscope.h 作用域模板类
├── hstring.h 字符串操作
├── hthreadpool.h 线程池
├── hurl.h URL操作
├── ifconfig.h 网络配置(ifconfig实现)
├── iniparser.h INI解析
├── json.hpp JSON解析
├── singleton.h 单例模式宏
└── ThreadLocalStorage.h 线程本地存储类
```

View File

@@ -0,0 +1,32 @@
#include "ThreadLocalStorage.h"
#include "hthread.h"
namespace hv {
ThreadLocalStorage ThreadLocalStorage::tls[ThreadLocalStorage::MAX_NUM];
void ThreadLocalStorage::set(int idx, void* val) {
return tls[idx].set(val);
}
void* ThreadLocalStorage::get(int idx) {
return tls[idx].get();
}
void ThreadLocalStorage::setThreadName(const char* name) {
set(THREAD_NAME, (void*)name);
}
const char* ThreadLocalStorage::threadName() {
void* value = get(THREAD_NAME);
if (value) {
return (char*)value;
}
static char unnamed[32] = {0};
snprintf(unnamed, sizeof(unnamed)-1, "thread-%ld", hv_gettid());
return unnamed;
}
}

View File

@@ -0,0 +1,67 @@
#ifndef HV_THREAD_LOCAL_STORAGE_H_
#define HV_THREAD_LOCAL_STORAGE_H_
#include "hexport.h"
#include "hplatform.h"
#ifdef OS_WIN
#define hthread_key_t DWORD
#define INVALID_HTHREAD_KEY 0xFFFFFFFF
#define hthread_key_create(pkey) *pkey = TlsAlloc()
#define hthread_key_delete TlsFree
#define hthread_get_value TlsGetValue
#define hthread_set_value TlsSetValue
#else
#define hthread_key_t pthread_key_t
#define INVALID_HTHREAD_KEY 0xFFFFFFFF
#define hthread_key_create(pkey) pthread_key_create(pkey, NULL)
#define hthread_key_delete pthread_key_delete
#define hthread_get_value pthread_getspecific
#define hthread_set_value pthread_setspecific
#endif
#ifdef __cplusplus
namespace hv {
class HV_EXPORT ThreadLocalStorage {
public:
enum {
THREAD_NAME = 0,
EVENT_LOOP = 1,
MAX_NUM = 16,
};
ThreadLocalStorage() {
hthread_key_create(&key);
}
~ThreadLocalStorage() {
hthread_key_delete(key);
}
void set(void* val) {
hthread_set_value(key, val);
}
void* get() {
return hthread_get_value(key);
}
static void set(int idx, void* val);
static void* get(int idx);
static void setThreadName(const char* name);
static const char* threadName();
private:
hthread_key_t key;
static ThreadLocalStorage tls[MAX_NUM];
};
}
#endif
#endif // HV_THREAD_LOCAL_STORAGE_H_

7
third_party/libhv/cpputil/hasync.cpp vendored Executable file
View File

@@ -0,0 +1,7 @@
#include "hasync.h"
namespace hv {
SINGLETON_IMPL(GlobalThreadPool)
}

49
third_party/libhv/cpputil/hasync.h vendored Executable file
View File

@@ -0,0 +1,49 @@
#ifndef HV_ASYNC_H_
#define HV_ASYNC_H_
#include "hexport.h"
#include "hthreadpool.h"
#include "singleton.h"
namespace hv {
class HV_EXPORT GlobalThreadPool : public HThreadPool {
SINGLETON_DECL(GlobalThreadPool)
protected:
GlobalThreadPool() : HThreadPool() {}
~GlobalThreadPool() {}
};
/*
* return a future, calling future.get() will wait task done and return RetType.
* async(fn, args...)
* async(std::bind(&Class::mem_fn, &obj))
* async(std::mem_fn(&Class::mem_fn, &obj))
*
*/
template<class Fn, class... Args>
auto async(Fn&& fn, Args&&... args) -> std::future<decltype(fn(args...))> {
return GlobalThreadPool::instance()->commit(std::forward<Fn>(fn), std::forward<Args>(args)...);
}
class async {
public:
static void startup(int min_threads = DEFAULT_THREAD_POOL_MIN_THREAD_NUM,
int max_threads = DEFAULT_THREAD_POOL_MAX_THREAD_NUM,
int max_idle_ms = DEFAULT_THREAD_POOL_MAX_IDLE_TIME) {
GlobalThreadPool* gtp = GlobalThreadPool::instance();
if (gtp->isStarted()) return;
gtp->setMinThreadNum(min_threads);
gtp->setMaxThreadNum(max_threads);
gtp->setMaxIdleTime(max_idle_ms);
gtp->start();
}
static void cleanup() {
GlobalThreadPool::exitInstance();
}
};
} // end namespace hv
#endif // HV_ASYNC_H_

88
third_party/libhv/cpputil/hdir.cpp vendored Executable file
View File

@@ -0,0 +1,88 @@
#include "hdir.h"
#include "hplatform.h"
#ifdef OS_WIN
//FILETIME starts from 1601-01-01 UTC, epoch from 1970-01-01 UTC
//FILETIME unit (100ns)
#define FILETIME_EPOCH_DIFF 11644473600 // s
time_t FileTime2Epoch(FILETIME filetime) {
uint64_t ll = (((uint64_t)filetime.dwHighDateTime) << 32) | filetime.dwLowDateTime;
ll /= 1e7; // s
return ll - FILETIME_EPOCH_DIFF;
}
#endif
static bool less(const hdir_t& lhs, const hdir_t& rhs) {
return stricmp(lhs.name, rhs.name) < 0;
}
int listdir(const char* dir, std::list<hdir_t>& dirs) {
int dirlen = strlen(dir);
if (dirlen > 256) {
return -1;
}
char path[512];
strcpy(path, dir);
if (dir[dirlen-1] != '/') {
strcat(path, "/");
++dirlen;
}
dirs.clear();
#ifdef OS_UNIX
// opendir -> readdir -> closedir
DIR* dp = opendir(dir);
if (dp == NULL) return -1;
struct dirent* result = NULL;
struct stat st;
hdir_t tmp;
while ((result = readdir(dp))) {
memset(&tmp, 0, sizeof(hdir_t));
strncpy(tmp.name, result->d_name, sizeof(tmp.name));
strncpy(path+dirlen, result->d_name, sizeof(path)-dirlen);
if (lstat(path, &st) == 0) {
if (S_ISREG(st.st_mode)) tmp.type = 'f';
else if (S_ISDIR(st.st_mode)) tmp.type = 'd';
else if (S_ISLNK(st.st_mode)) tmp.type = 'l';
else if (S_ISBLK(st.st_mode)) tmp.type = 'b';
else if (S_ISCHR(st.st_mode)) tmp.type = 'c';
else if (S_ISSOCK(st.st_mode)) tmp.type = 's';
else if (S_ISFIFO(st.st_mode)) tmp.type = 'p';
else tmp.type = '-';
tmp.mode = st.st_mode & 0777;
tmp.size = st.st_size;
tmp.atime = st.st_atime;
tmp.mtime = st.st_mtime;
tmp.ctime = st.st_ctime;
}
dirs.push_back(tmp);
}
closedir(dp);
#elif defined(OS_WIN)
// FindFirstFile -> FindNextFile -> FindClose
strcat(path, "*");
WIN32_FIND_DATAA data;
HANDLE h = FindFirstFileA(path, &data);
if (h == NULL) {
return -1;
}
hdir_t tmp;
do {
memset(&tmp, 0, sizeof(hdir_t));
strncpy(tmp.name, data.cFileName, sizeof(tmp.name));
tmp.type = 'f';
if (data.dwFileAttributes & _A_SUBDIR) {
tmp.type = 'd';
}
tmp.mode = 0777;
tmp.size = (((uint64_t)data.nFileSizeHigh) << 32) | data.nFileSizeLow;
tmp.atime = FileTime2Epoch(data.ftLastAccessTime);
tmp.mtime = FileTime2Epoch(data.ftLastWriteTime);
tmp.ctime = FileTime2Epoch(data.ftCreationTime);
dirs.push_back(tmp);
} while (FindNextFileA(h, &data));
FindClose(h);
#endif
dirs.sort(less);
return dirs.size();
}

69
third_party/libhv/cpputil/hdir.h vendored Executable file
View File

@@ -0,0 +1,69 @@
#ifndef HV_DIR_H_
#define HV_DIR_H_
/*
*@code
int main(int argc, char* argv[]) {
const char* dir = ".";
if (argc > 1) {
dir = argv[1];
}
std::list<hdir_t> dirs;
listdir(dir, dirs);
for (auto& item : dirs) {
printf("%c%c%c%c%c%c%c%c%c%c\t",
item.type,
item.mode & 0400 ? 'r' : '-',
item.mode & 0200 ? 'w' : '-',
item.mode & 0100 ? 'x' : '-',
item.mode & 0040 ? 'r' : '-',
item.mode & 0020 ? 'w' : '-',
item.mode & 0010 ? 'x' : '-',
item.mode & 0004 ? 'r' : '-',
item.mode & 0002 ? 'w' : '-',
item.mode & 0001 ? 'x' : '-');
float hsize;
if (item.size < 1024) {
printf("%lu\t", item.size);
}
else if ((hsize = item.size/1024.0f) < 1024.0f) {
printf("%.1fK\t", hsize);
}
else if ((hsize /= 1024.0f) < 1024.0f) {
printf("%.1fM\t", hsize);
}
else {
hsize /= 1024.0f;
printf("%.1fG\t", hsize);
}
struct tm* tm = localtime(&item.mtime);
printf("%04d-%02d-%02d %02d:%02d:%02d\t",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
printf("%s%s\n", item.name, item.type == 'd' ? "/" : "");
}
return 0;
}
*/
#include <string.h>
#include <time.h>
#include <list>
#include "hexport.h"
typedef struct hdir_s {
char name[256];
char type; // f:file d:dir l:link b:block c:char s:socket p:pipe
char reserverd;
unsigned short mode;
size_t size;
time_t atime;
time_t mtime;
time_t ctime;
} hdir_t;
// listdir: same as ls on unix, dir on win
HV_EXPORT int listdir(const char* dir, std::list<hdir_t>& dirs);
#endif // HV_DIR_H_

134
third_party/libhv/cpputil/hfile.h vendored Executable file
View File

@@ -0,0 +1,134 @@
#ifndef HV_FILE_H_
#define HV_FILE_H_
#include <string> // for std::string
#include "hplatform.h" // for stat
#include "hbuf.h" // for HBuf
class HFile {
public:
HFile() {
filepath[0] = '\0';
fp = NULL;
}
~HFile() {
close();
}
int open(const char* filepath, const char* mode) {
close();
strncpy(this->filepath, filepath, MAX_PATH - 1);
fp = fopen(filepath, mode);
return fp ? 0 : errno;
}
void close() {
if (fp) {
fclose(fp);
fp = NULL;
}
}
bool isopen() {
return fp != NULL;
}
int remove() {
close();
return ::remove(filepath);
}
int rename(const char* newpath) {
close();
return ::rename(filepath, newpath);
}
size_t read(void* ptr, size_t len) {
return fread(ptr, 1, len, fp);
}
size_t write(const void* ptr, size_t len) {
return fwrite(ptr, 1, len, fp);
}
size_t write(const std::string& str) {
return write(str.c_str(), str.length());
}
int seek(size_t offset, int whence = SEEK_SET) {
return fseek(fp, offset, whence);
}
int tell() {
return ftell(fp);
}
int flush() {
return fflush(fp);
}
static size_t size(const char* filepath) {
struct stat st;
memset(&st, 0, sizeof(st));
stat(filepath, &st);
return st.st_size;
}
size_t size() {
return HFile::size(filepath);
}
size_t readall(HBuf& buf) {
size_t filesize = size();
if (filesize == 0) return 0;
buf.resize(filesize);
return fread(buf.base, 1, filesize, fp);
}
size_t readall(std::string& str) {
size_t filesize = size();
if (filesize == 0) return 0;
str.resize(filesize);
return fread((void*)str.data(), 1, filesize, fp);
}
bool readline(std::string& str) {
str.clear();
char ch;
while (fread(&ch, 1, 1, fp)) {
if (ch == '\n') {
// unix: LF
return true;
}
if (ch == '\r') {
// dos: CRLF
// read LF
if (fread(&ch, 1, 1, fp) && ch != '\n') {
// mac: CR
fseek(fp, -1, SEEK_CUR);
}
return true;
}
str += ch;
}
return str.length() != 0;
}
int readrange(std::string& str, size_t from = 0, size_t to = 0) {
size_t filesize = size();
if (filesize == 0) return 0;
if (to == 0 || to >= filesize) to = filesize - 1;
size_t readbytes = to - from + 1;
str.resize(readbytes);
fseek(fp, from, SEEK_SET);
return fread((void*)str.data(), 1, readbytes, fp);
}
public:
char filepath[MAX_PATH];
FILE* fp;
};
#endif // HV_FILE_H_

55
third_party/libhv/cpputil/hmap.h vendored Executable file
View File

@@ -0,0 +1,55 @@
#ifndef HV_MAP_H_
#define HV_MAP_H_
#include "hconfig.h"
#include <map>
#include <string>
// MultiMap
namespace std {
/*
int main() {
std::MultiMap<std::string, std::string> kvs;
kvs["name"] = "hw";
kvs["filename"] = "1.jpg";
kvs["filename"] = "2.jpg";
//kvs.insert(std::pair<std::string,std::string>("name", "hw"));
//kvs.insert(std::pair<std::string,std::string>("filename", "1.jpg"));
//kvs.insert(std::pair<std::string,std::string>("filename", "2.jpg"));
for (auto& pair : kvs) {
printf("%s:%s\n", pair.first.c_str(), pair.second.c_str());
}
auto iter = kvs.find("filename");
if (iter != kvs.end()) {
for (int i = 0; i < kvs.count("filename"); ++i, ++iter) {
printf("%s:%s\n", iter->first.c_str(), iter->second.c_str());
}
}
return 0;
}
*/
template<typename Key,typename Value>
class MultiMap : public multimap<Key, Value> {
public:
Value& operator[](Key key) {
auto iter = this->insert(std::pair<Key,Value>(key,Value()));
return (*iter).second;
}
};
}
#ifdef USE_MULTIMAP
#define HV_MAP std::MultiMap
#else
#define HV_MAP std::map
#endif
// KeyValue
namespace hv {
typedef std::map<std::string, std::string> keyval_t;
typedef std::MultiMap<std::string, std::string> multi_keyval_t;
typedef HV_MAP<std::string, std::string> KeyValue;
}
#endif // HV_MAP_H_

183
third_party/libhv/cpputil/hobjectpool.h vendored Executable file
View File

@@ -0,0 +1,183 @@
#ifndef HV_OBJECT_POOL_H_
#define HV_OBJECT_POOL_H_
/*
* @usage unittest/objectpool_test.cpp
*/
#include <list>
#include <memory>
#include <mutex>
#include <condition_variable>
#define DEFAULT_OBJECT_POOL_INIT_NUM 0
#define DEFAULT_OBJECT_POOL_MAX_NUM 4
#define DEFAULT_OBJECT_POOL_TIMEOUT 3000 // ms
template<class T>
class HObjectFactory {
public:
static T* create() {
return new T;
}
};
template<class T, class TFactory = HObjectFactory<T>>
class HObjectPool {
public:
HObjectPool(
int init_num = DEFAULT_OBJECT_POOL_INIT_NUM,
int max_num = DEFAULT_OBJECT_POOL_MAX_NUM,
int timeout = DEFAULT_OBJECT_POOL_TIMEOUT)
: _max_num(max_num)
, _timeout(timeout)
{
for (int i = 0; i < init_num; ++i) {
T* p = TFactory::create();
if (p) {
objects_.push_back(std::shared_ptr<T>(p));
}
}
_object_num = objects_.size();
}
~HObjectPool() {}
int ObjectNum() { return _object_num; }
int IdleNum() { return objects_.size(); }
int BorrowNum() { return ObjectNum() - IdleNum(); }
std::shared_ptr<T> TryBorrow() {
std::shared_ptr<T> pObj = NULL;
std::lock_guard<std::mutex> locker(mutex_);
if (!objects_.empty()) {
pObj = objects_.front();
objects_.pop_front();
}
return pObj;
}
std::shared_ptr<T> Borrow() {
std::shared_ptr<T> pObj = TryBorrow();
if (pObj) {
return pObj;
}
std::unique_lock<std::mutex> locker(mutex_);
if (_object_num < _max_num) {
++_object_num;
// NOTE: unlock to avoid TFactory::create block
mutex_.unlock();
T* p = TFactory::create();
mutex_.lock();
if (!p) --_object_num;
return std::shared_ptr<T>(p);
}
if (_timeout > 0) {
std::cv_status status = cond_.wait_for(locker, std::chrono::milliseconds(_timeout));
if (status == std::cv_status::timeout) {
return NULL;
}
if (!objects_.empty()) {
pObj = objects_.front();
objects_.pop_front();
return pObj;
}
else {
// WARN: No idle object
}
}
return pObj;
}
void Return(std::shared_ptr<T>& pObj) {
if (!pObj) return;
std::lock_guard<std::mutex> locker(mutex_);
objects_.push_back(pObj);
cond_.notify_one();
}
bool Add(std::shared_ptr<T>& pObj) {
std::lock_guard<std::mutex> locker(mutex_);
if (_object_num >= _max_num) {
return false;
}
objects_.push_back(pObj);
++_object_num;
cond_.notify_one();
return true;
}
bool Remove(std::shared_ptr<T>& pObj) {
std::lock_guard<std::mutex> locker(mutex_);
auto iter = objects_.begin();
while (iter != objects_.end()) {
if (*iter == pObj) {
iter = objects_.erase(iter);
--_object_num;
return true;
}
else {
++iter;
}
}
return false;
}
void Clear() {
std::lock_guard<std::mutex> locker(mutex_);
objects_.clear();
_object_num = 0;
}
int _object_num;
int _max_num;
int _timeout;
private:
std::list<std::shared_ptr<T>> objects_;
std::mutex mutex_;
std::condition_variable cond_;
};
template<class T, class TFactory = HObjectFactory<T>>
class HPoolObject {
public:
typedef HObjectPool<T, TFactory> PoolType;
HPoolObject(PoolType& pool) : pool_(pool)
{
sptr_ = pool_.Borrow();
}
~HPoolObject() {
if (sptr_) {
pool_.Return(sptr_);
}
}
HPoolObject(const HPoolObject<T>&) = delete;
HPoolObject<T>& operator=(const HPoolObject<T>&) = delete;
T* get() {
return sptr_.get();
}
operator bool() {
return sptr_.get() != NULL;
}
T* operator->() {
return sptr_.get();
}
T operator*() {
return *sptr_.get();
}
private:
PoolType& pool_;
std::shared_ptr<T> sptr_;
};
#endif // HV_OBJECT_POOL_H_

112
third_party/libhv/cpputil/hpath.cpp vendored Executable file
View File

@@ -0,0 +1,112 @@
#include "hpath.h"
#include "hplatform.h"
bool HPath::exists(const char* path) {
return access(path, 0) == 0;
}
bool HPath::isdir(const char* path) {
if (access(path, 0) != 0) return false;
struct stat st;
memset(&st, 0, sizeof(st));
stat(path, &st);
return S_ISDIR(st.st_mode);
}
bool HPath::isfile(const char* path) {
if (access(path, 0) != 0) return false;
struct stat st;
memset(&st, 0, sizeof(st));
stat(path, &st);
return S_ISREG(st.st_mode);
}
bool HPath::islink(const char* path) {
#ifdef OS_WIN
return HPath::isdir(path) && (GetFileAttributesA(path) & FILE_ATTRIBUTE_REPARSE_POINT);
#else
if (access(path, 0) != 0) return false;
struct stat st;
memset(&st, 0, sizeof(st));
lstat(path, &st);
return S_ISLNK(st.st_mode);
#endif
}
std::string HPath::basename(const std::string& filepath) {
std::string::size_type pos1 = filepath.find_last_not_of("/\\");
if (pos1 == std::string::npos) {
return "/";
}
std::string::size_type pos2 = filepath.find_last_of("/\\", pos1);
if (pos2 == std::string::npos) {
pos2 = 0;
} else {
pos2++;
}
return filepath.substr(pos2, pos1-pos2+1);
}
std::string HPath::dirname(const std::string& filepath) {
std::string::size_type pos1 = filepath.find_last_not_of("/\\");
if (pos1 == std::string::npos) {
return "/";
}
std::string::size_type pos2 = filepath.find_last_of("/\\", pos1);
if (pos2 == std::string::npos) {
return ".";
} else if (pos2 == 0) {
pos2 = 1;
}
return filepath.substr(0, pos2);
}
std::string HPath::filename(const std::string& filepath) {
std::string::size_type pos1 = filepath.find_last_of("/\\");
if (pos1 == std::string::npos) {
pos1 = 0;
} else {
pos1++;
}
std::string file = filepath.substr(pos1);
std::string::size_type pos2 = file.find_last_of(".");
if (pos2 == std::string::npos) {
return file;
}
return file.substr(0, pos2);
}
std::string HPath::suffixname(const std::string& filepath) {
std::string::size_type pos1 = filepath.find_last_of("/\\");
if (pos1 == std::string::npos) {
pos1 = 0;
} else {
pos1++;
}
std::string file = filepath.substr(pos1);
std::string::size_type pos2 = file.find_last_of(".");
if (pos2 == std::string::npos) {
return "";
}
return file.substr(pos2+1);
}
std::string HPath::join(const std::string& dir, const std::string& filename) {
char separator = '/';
#ifdef OS_WIN
if (dir.find_first_of("\\") != std::string::npos) {
separator = '\\';
}
#endif
std::string filepath(dir);
if (dir[dir.length()-1] != separator) {
filepath += separator;
}
filepath += filename;
return filepath;
}

28
third_party/libhv/cpputil/hpath.h vendored Executable file
View File

@@ -0,0 +1,28 @@
#ifndef HV_PATH_H_
#define HV_PATH_H_
#include <string> // for std::string
#include "hexport.h"
class HV_EXPORT HPath {
public:
static bool exists(const char* path);
static bool isdir(const char* path);
static bool isfile(const char* path);
static bool islink(const char* path);
// filepath = /mnt/share/image/test.jpg
// basename = test.jpg
// dirname = /mnt/share/image
// filename = test
// suffixname = jpg
static std::string basename(const std::string& filepath);
static std::string dirname(const std::string& filepath);
static std::string filename(const std::string& filepath);
static std::string suffixname(const std::string& filepath);
static std::string join(const std::string& dir, const std::string& filename);
};
#endif // HV_PATH_H_

79
third_party/libhv/cpputil/hscope.h vendored Executable file
View File

@@ -0,0 +1,79 @@
#ifndef HV_SCOPE_H_
#define HV_SCOPE_H_
#include <functional>
typedef std::function<void()> Function;
#include "hdef.h"
// same as golang defer
class Defer {
public:
Defer(Function&& fn) : _fn(std::move(fn)) {}
~Defer() { if(_fn) _fn();}
private:
Function _fn;
};
#define defer(code) Defer STRINGCAT(_defer_, __LINE__)([&](){code});
class ScopeCleanup {
public:
template<typename Fn, typename... Args>
ScopeCleanup(Fn&& fn, Args&&... args) {
_cleanup = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);
}
~ScopeCleanup() {
_cleanup();
}
private:
Function _cleanup;
};
template<typename T>
class ScopeFree {
public:
ScopeFree(T* p) : _p(p) {}
~ScopeFree() {SAFE_FREE(_p);}
private:
T* _p;
};
template<typename T>
class ScopeDelete {
public:
ScopeDelete(T* p) : _p(p) {}
~ScopeDelete() {SAFE_DELETE(_p);}
private:
T* _p;
};
template<typename T>
class ScopeDeleteArray {
public:
ScopeDeleteArray(T* p) : _p(p) {}
~ScopeDeleteArray() {SAFE_DELETE_ARRAY(_p);}
private:
T* _p;
};
template<typename T>
class ScopeRelease {
public:
ScopeRelease(T* p) : _p(p) {}
~ScopeRelease() {SAFE_RELEASE(_p);}
private:
T* _p;
};
template<typename T>
class ScopeLock {
public:
ScopeLock(T& mutex) : _mutex(mutex) {_mutex.lock();}
~ScopeLock() {_mutex.unlock();}
private:
T& _mutex;
};
#endif // HV_SCOPE_H_

227
third_party/libhv/cpputil/hstring.cpp vendored Executable file
View File

@@ -0,0 +1,227 @@
#include "hstring.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
namespace hv {
std::string empty_string;
std::map<std::string, std::string> empty_map;
std::string& toupper(std::string& str) {
// std::transform(str.begin(), str.end(), str.begin(), ::toupper);
char* p = (char*)str.c_str();
while (*p != '\0') {
if (*p >= 'a' && *p <= 'z') {
*p &= ~0x20;
}
++p;
}
return str;
}
std::string& tolower(std::string& str) {
// std::transform(str.begin(), str.end(), str.begin(), ::tolower);
char* p = (char*)str.c_str();
while (*p != '\0') {
if (*p >= 'A' && *p <= 'Z') {
*p |= 0x20;
}
++p;
}
return str;
}
std::string& reverse(std::string& str) {
// std::reverse(str.begin(), str.end());
char* b = (char*)str.c_str();
char* e = b + str.length() - 1;
char tmp;
while (e > b) {
tmp = *e;
*e = *b;
*b = tmp;
--e;
++b;
}
return str;
}
bool startswith(const std::string& str, const std::string& start) {
if (str.length() < start.length()) return false;
return str.compare(0, start.length(), start) == 0;
}
bool endswith(const std::string& str, const std::string& end) {
if (str.length() < end.length()) return false;
return str.compare(str.length() - end.length(), end.length(), end) == 0;
}
bool contains(const std::string& str, const std::string& sub) {
if (str.length() < sub.length()) return false;
return str.find(sub) != std::string::npos;
}
static inline int vscprintf(const char* fmt, va_list ap) {
return vsnprintf(NULL, 0, fmt, ap);
}
std::string asprintf(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
int len = vscprintf(fmt, ap);
va_end(ap);
std::string str;
str.reserve(len+1);
// must resize to set str.size
str.resize(len);
// must recall va_start on unix
va_start(ap, fmt);
vsnprintf((char*)str.data(), len+1, fmt, ap);
va_end(ap);
return str;
}
StringList split(const std::string& str, char delim) {
/*
std::stringstream ss;
ss << str;
string item;
StringList res;
while (std::getline(ss, item, delim)) {
res.push_back(item);
}
return res;
*/
const char* p = str.c_str();
const char* value = p;
StringList res;
while (*p != '\0') {
if (*p == delim) {
res.push_back(std::string(value, p-value));
value = p+1;
}
++p;
}
res.push_back(value);
return res;
}
hv::KeyValue splitKV(const std::string& str, char kv_kv, char k_v) {
enum {
s_key,
s_value,
} state = s_key;
const char* p = str.c_str();
const char* key = p;
const char* value = NULL;
int key_len = 0;
int value_len = 0;
hv::KeyValue kvs;
while (*p != '\0') {
if (*p == kv_kv) {
if (key_len && value_len) {
kvs[std::string(key, key_len)] = std::string(value, value_len);
key_len = value_len = 0;
}
state = s_key;
key = p+1;
}
else if (*p == k_v && state != s_value) {
state = s_value;
value = p+1;
}
else {
state == s_key ? ++key_len : ++value_len;
}
++p;
}
if (key_len && value_len) {
kvs[std::string(key, key_len)] = std::string(value, value_len);
}
return kvs;
}
std::string trim(const std::string& str, const char* chars) {
std::string::size_type pos1 = str.find_first_not_of(chars);
if (pos1 == std::string::npos) return "";
std::string::size_type pos2 = str.find_last_not_of(chars);
return str.substr(pos1, pos2-pos1+1);
}
std::string ltrim(const std::string& str, const char* chars) {
std::string::size_type pos = str.find_first_not_of(chars);
if (pos == std::string::npos) return "";
return str.substr(pos);
}
std::string rtrim(const std::string& str, const char* chars) {
std::string::size_type pos = str.find_last_not_of(chars);
return str.substr(0, pos+1);
}
std::string trim_pairs(const std::string& str, const char* pairs) {
const char* s = str.c_str();
const char* e = str.c_str() + str.size() - 1;
const char* p = pairs;
bool is_pair = false;
while (*p != '\0' && *(p+1) != '\0') {
if (*s == *p && *e == *(p+1)) {
is_pair = true;
break;
}
p += 2;
}
return is_pair ? str.substr(1, str.size()-2) : str;
}
std::string replace(const std::string& str, const std::string& find, const std::string& rep) {
std::string res(str);
std::string::size_type pos = res.find(find);
if (pos != std::string::npos) {
res.replace(pos, find.size(), rep);
}
return res;
}
std::string replaceAll(const std::string& str, const std::string& find, const std::string& rep) {
std::string::size_type pos = 0;
std::string::size_type a = find.size();
std::string::size_type b = rep.size();
std::string res(str);
while ((pos = res.find(find, pos)) != std::string::npos) {
res.replace(pos, a, rep);
pos += b;
}
return res;
}
void NetAddr::from_string(const std::string& ipport) {
auto pos = ipport.find_last_of(':');
if (pos != std::string::npos) {
ip = trim_pairs(ipport.substr(0, pos), "[]");
std::string strPort = ipport.substr(pos + 1);
port = atoi(strPort.c_str());
} else if (ipport.find('.') != std::string::npos) {
ip = ipport;
port = 0;
} else {
port = atoi(ipport.c_str());
}
}
std::string NetAddr::to_string() {
const char* fmt = "%s:%d";
if (ip.find(':') != std::string::npos) {
fmt = "[%s]:%d";
}
return hv::asprintf(fmt, ip.c_str(), port);
}
} // end namespace hv

92
third_party/libhv/cpputil/hstring.h vendored Executable file
View File

@@ -0,0 +1,92 @@
#ifndef HV_STRING_H_
#define HV_STRING_H_
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include "hexport.h"
#include "hplatform.h"
#include "hmap.h"
#define SPACE_CHARS " \t\r\n"
#define PAIR_CHARS "{}[]()<>\"\"\'\'``"
namespace hv {
HV_EXPORT extern std::string empty_string;
HV_EXPORT extern std::map<std::string, std::string> empty_map;
typedef std::vector<std::string> StringList;
// std::map<std::string, std::string, StringCaseLess>
class StringCaseLess : public std::less<std::string> {
public:
bool operator()(const std::string& lhs, const std::string& rhs) const {
return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
}
};
// NOTE: low-version NDK not provide std::to_string
template<typename T>
HV_INLINE std::string to_string(const T& t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
template<typename T>
HV_INLINE T from_string(const std::string& str) {
T t;
std::istringstream iss(str);
iss >> t;
return t;
}
template<typename T>
HV_INLINE void print(const T& t) {
std::cout << t;
}
template<typename T>
HV_INLINE void println(const T& t) {
std::cout << t << std::endl;
}
HV_EXPORT std::string& toupper(std::string& str);
HV_EXPORT std::string& tolower(std::string& str);
HV_EXPORT std::string& reverse(std::string& str);
HV_EXPORT bool startswith(const std::string& str, const std::string& start);
HV_EXPORT bool endswith(const std::string& str, const std::string& end);
HV_EXPORT bool contains(const std::string& str, const std::string& sub);
HV_EXPORT std::string asprintf(const char* fmt, ...);
// x,y,z
HV_EXPORT StringList split(const std::string& str, char delim = ',');
// k1=v1&k2=v2
HV_EXPORT hv::KeyValue splitKV(const std::string& str, char kv_kv = '&', char k_v = '=');
HV_EXPORT std::string trim(const std::string& str, const char* chars = SPACE_CHARS);
HV_EXPORT std::string ltrim(const std::string& str, const char* chars = SPACE_CHARS);
HV_EXPORT std::string rtrim(const std::string& str, const char* chars = SPACE_CHARS);
HV_EXPORT std::string trim_pairs(const std::string& str, const char* pairs = PAIR_CHARS);
HV_EXPORT std::string replace(const std::string& str, const std::string& find, const std::string& rep);
HV_EXPORT std::string replaceAll(const std::string& str, const std::string& find, const std::string& rep);
struct HV_EXPORT NetAddr {
std::string ip;
int port;
NetAddr() : port(0) {}
NetAddr(const std::string& _ip, int _port) : ip(_ip), port(_port) {}
NetAddr(const std::string& ipport) { from_string(ipport); }
void from_string(const std::string& ipport);
std::string to_string();
};
} // end namespace hv
#endif // HV_STRING_H_

249
third_party/libhv/cpputil/hthreadpool.h vendored Executable file
View File

@@ -0,0 +1,249 @@
#ifndef HV_THREAD_POOL_H_
#define HV_THREAD_POOL_H_
/*
* @usage unittest/threadpool_test.cpp
*/
#include <time.h>
#include <thread>
#include <list>
#include <queue>
#include <functional>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <future>
#include <memory>
#include <utility>
#include <chrono>
#define DEFAULT_THREAD_POOL_MIN_THREAD_NUM 1
#define DEFAULT_THREAD_POOL_MAX_THREAD_NUM std::thread::hardware_concurrency()
#define DEFAULT_THREAD_POOL_MAX_IDLE_TIME 60000 // ms
class HThreadPool {
public:
using Task = std::function<void()>;
HThreadPool(int min_threads = DEFAULT_THREAD_POOL_MIN_THREAD_NUM,
int max_threads = DEFAULT_THREAD_POOL_MAX_THREAD_NUM,
int max_idle_ms = DEFAULT_THREAD_POOL_MAX_IDLE_TIME)
: min_thread_num(min_threads)
, max_thread_num(max_threads)
, max_idle_time(max_idle_ms)
, status(STOP)
, cur_thread_num(0)
, idle_thread_num(0)
{}
virtual ~HThreadPool() {
stop();
}
void setMinThreadNum(int min_threads) {
min_thread_num = min_threads;
}
void setMaxThreadNum(int max_threads) {
max_thread_num = max_threads;
}
void setMaxIdleTime(int ms) {
max_idle_time = ms;
}
int currentThreadNum() {
return cur_thread_num;
}
int idleThreadNum() {
return idle_thread_num;
}
size_t taskNum() {
std::lock_guard<std::mutex> locker(task_mutex);
return tasks.size();
}
bool isStarted() {
return status != STOP;
}
bool isStopped() {
return status == STOP;
}
int start(int start_threads = 0) {
if (status != STOP) return -1;
status = RUNNING;
if (start_threads < min_thread_num) start_threads = min_thread_num;
if (start_threads > max_thread_num) start_threads = max_thread_num;
for (int i = 0; i < start_threads; ++i) {
createThread();
}
return 0;
}
int stop() {
if (status == STOP) return -1;
status = STOP;
task_cond.notify_all();
for (auto& i : threads) {
if (i.thread->joinable()) {
i.thread->join();
}
}
threads.clear();
cur_thread_num = 0;
idle_thread_num = 0;
return 0;
}
int pause() {
if (status == RUNNING) {
status = PAUSE;
}
return 0;
}
int resume() {
if (status == PAUSE) {
status = RUNNING;
}
return 0;
}
int wait() {
while (status != STOP) {
if (tasks.empty() && idle_thread_num == cur_thread_num) {
break;
}
std::this_thread::yield();
}
return 0;
}
/*
* return a future, calling future.get() will wait task done and return RetType.
* commit(fn, args...)
* commit(std::bind(&Class::mem_fn, &obj))
* commit(std::mem_fn(&Class::mem_fn, &obj))
*
*/
template<class Fn, class... Args>
auto commit(Fn&& fn, Args&&... args) -> std::future<decltype(fn(args...))> {
if (status == STOP) start();
if (idle_thread_num <= tasks.size() && cur_thread_num < max_thread_num) {
createThread();
}
using RetType = decltype(fn(args...));
auto task = std::make_shared<std::packaged_task<RetType()> >(
std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...));
std::future<RetType> future = task->get_future();
{
std::lock_guard<std::mutex> locker(task_mutex);
tasks.emplace([task]{
(*task)();
});
}
task_cond.notify_one();
return future;
}
protected:
bool createThread() {
if (cur_thread_num >= max_thread_num) return false;
std::thread* thread = new std::thread([this] {
while (status != STOP) {
while (status == PAUSE) {
std::this_thread::yield();
}
Task task;
{
std::unique_lock<std::mutex> locker(task_mutex);
task_cond.wait_for(locker, std::chrono::milliseconds(max_idle_time), [this]() {
return status == STOP || !tasks.empty();
});
if (status == STOP) return;
if (tasks.empty()) {
if (cur_thread_num > min_thread_num) {
delThread(std::this_thread::get_id());
return;
}
continue;
}
--idle_thread_num;
task = std::move(tasks.front());
tasks.pop();
}
if (task) {
task();
++idle_thread_num;
}
}
});
addThread(thread);
return true;
}
void addThread(std::thread* thread) {
thread_mutex.lock();
++cur_thread_num;
++idle_thread_num;
ThreadData data;
data.thread = std::shared_ptr<std::thread>(thread);
data.id = thread->get_id();
data.status = RUNNING;
data.start_time = time(NULL);
data.stop_time = 0;
threads.emplace_back(data);
thread_mutex.unlock();
}
void delThread(std::thread::id id) {
time_t now = time(NULL);
thread_mutex.lock();
--cur_thread_num;
--idle_thread_num;
auto iter = threads.begin();
while (iter != threads.end()) {
if (iter->status == STOP && now > iter->stop_time) {
if (iter->thread->joinable()) {
iter->thread->join();
iter = threads.erase(iter);
continue;
}
} else if (iter->id == id) {
iter->status = STOP;
iter->stop_time = time(NULL);
}
++iter;
}
thread_mutex.unlock();
}
public:
int min_thread_num;
int max_thread_num;
int max_idle_time;
protected:
enum Status {
STOP,
RUNNING,
PAUSE,
};
struct ThreadData {
std::shared_ptr<std::thread> thread;
std::thread::id id;
Status status;
time_t start_time;
time_t stop_time;
};
std::atomic<Status> status;
std::atomic<int> cur_thread_num;
std::atomic<int> idle_thread_num;
std::list<ThreadData> threads;
std::mutex thread_mutex;
std::queue<Task> tasks;
std::mutex task_mutex;
std::condition_variable task_cond;
};
#endif // HV_THREAD_POOL_H_

206
third_party/libhv/cpputil/hurl.cpp vendored Executable file
View File

@@ -0,0 +1,206 @@
#include "hurl.h"
#include "hdef.h"
#include "hbase.h"
/*
static bool Curl_isunreserved(unsigned char in)
{
switch(in) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e':
case 'f': case 'g': case 'h': case 'i': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'o':
case 'p': case 'q': case 'r': case 's': case 't':
case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E':
case 'F': case 'G': case 'H': case 'I': case 'J':
case 'K': case 'L': case 'M': case 'N': case 'O':
case 'P': case 'Q': case 'R': case 'S': case 'T':
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
case '-': case '.': case '_': case '~':
return TRUE;
default:
break;
}
return FLASE;
}
*/
static inline bool is_unambiguous(char c) {
return IS_ALPHANUM(c) ||
c == '-' ||
c == '_' ||
c == '.' ||
c == '~';
}
static inline bool char_in_str(char c, const char* str) {
const char* p = str;
while (*p && *p != c) ++p;
return *p != '\0';
}
static inline unsigned char hex2i(char hex) {
return hex <= '9' ? hex - '0' :
hex <= 'F' ? hex - 'A' + 10 : hex - 'a' + 10;
}
std::string HUrl::escape(const std::string& str, const char* unescaped_chars) {
std::string ostr;
static char tab[] = "0123456789ABCDEF";
const unsigned char* p = reinterpret_cast<const unsigned char*>(str.c_str());
char szHex[4] = "%00";
while (*p != '\0') {
if (is_unambiguous(*p) || char_in_str(*p, unescaped_chars)) {
ostr += *p;
}
else {
szHex[1] = tab[*p >> 4];
szHex[2] = tab[*p & 0xF];
ostr += szHex;
}
++p;
}
return ostr;
}
std::string HUrl::unescape(const std::string& str) {
std::string ostr;
const char* p = str.c_str();
while (*p != '\0') {
if (*p == '%' &&
IS_HEX(p[1]) &&
IS_HEX(p[2])) {
ostr += ((hex2i(p[1]) << 4) | hex2i(p[2]));
p += 3;
}
else {
if (*p == '+') {
ostr += ' ';
} else {
ostr += *p;
}
++p;
}
}
return ostr;
}
void HUrl::reset() {
url.clear();
scheme.clear();
username.clear();
password.clear();
host.clear();
port = 0;
path.clear();
query.clear();
fragment.clear();
}
bool HUrl::parse(const std::string& url) {
reset();
this->url = url;
hurl_t stURL;
if (hv_parse_url(&stURL, url.c_str()) != 0) {
return false;
}
int len = stURL.fields[HV_URL_SCHEME].len;
if (len > 0) {
scheme = url.substr(stURL.fields[HV_URL_SCHEME].off, len);
}
len = stURL.fields[HV_URL_USERNAME].len;
if (len > 0) {
username = url.substr(stURL.fields[HV_URL_USERNAME].off, len);
len = stURL.fields[HV_URL_PASSWORD].len;
if (len > 0) {
password = url.substr(stURL.fields[HV_URL_PASSWORD].off, len);
}
}
len = stURL.fields[HV_URL_HOST].len;
if (len > 0) {
host = url.substr(stURL.fields[HV_URL_HOST].off, len);
}
port = stURL.port;
len = stURL.fields[HV_URL_PATH].len;
if (len > 0) {
path = url.substr(stURL.fields[HV_URL_PATH].off, len);
} else {
path = "/";
}
len = stURL.fields[HV_URL_QUERY].len;
if (len > 0) {
query = url.substr(stURL.fields[HV_URL_QUERY].off, len);
}
len = stURL.fields[HV_URL_FRAGMENT].len;
if (len > 0) {
fragment = url.substr(stURL.fields[HV_URL_FRAGMENT].off, len);
}
return true;
}
const std::string& HUrl::dump() {
url.clear();
// scheme://
if (!scheme.empty()) {
url += scheme;
url += "://";
}
// user:pswd@
if (!username.empty()) {
url += username;
if (!password.empty()) {
url += ":";
url += password;
}
url += "@";
}
// host:port
if (!host.empty()) {
url += host;
if (port != 80 && port != 443) {
char buf[16] = {0};
snprintf(buf, sizeof(buf), ":%d", port);
url += port;
}
}
// /path
if (!path.empty()) {
url += path;
}
// ?query
if (!query.empty()) {
url += '?';
url += query;
}
// #fragment
if (!fragment.empty()) {
url += '#';
url += fragment;
}
return url;
}
namespace hv {
std::string escapeHTML(const std::string& str) {
std::string ostr;
const char* p = str.c_str();
while (*p != '\0') {
switch (*p) {
case '<': ostr += "&lt;"; break;
case '>': ostr += "&gt;"; break;
case '&': ostr += "&amp;"; break;
case '\"': ostr += "&quot;"; break;
case '\'': ostr += "&apos;"; break;
// case ' ': ostr += "&nbsp;"; break;
default: ostr += *p; break;
}
++p;
}
return ostr;
}
}

41
third_party/libhv/cpputil/hurl.h vendored Executable file
View File

@@ -0,0 +1,41 @@
#ifndef HV_URL_H_
#define HV_URL_H_
#include <string> // import std::string
#include "hexport.h"
class HV_EXPORT HUrl {
public:
static std::string escape(const std::string& str, const char* unescaped_chars = "");
static std::string unescape(const std::string& str);
HUrl() : port(0) {}
~HUrl() {}
void reset();
bool parse(const std::string& url);
const std::string& dump();
std::string url;
std::string scheme;
std::string username;
std::string password;
std::string host;
int port;
std::string path;
std::string query;
std::string fragment;
};
namespace hv {
HV_INLINE std::string escapeURL(const std::string& url) {
return HUrl::escape(url, ":/@?=&#+");
}
HV_EXPORT std::string escapeHTML(const std::string& str);
} // end namespace hv
#endif // HV_URL_H_

223
third_party/libhv/cpputil/ifconfig.cpp vendored Executable file
View File

@@ -0,0 +1,223 @@
#include "ifconfig.h"
#include "hplatform.h"
#ifdef OS_LINUX
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
int ifconfig(std::vector<ifconfig_t>& ifcs) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
return -10;
}
struct ifconf ifc;
char buf[1024];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
int iRet = ioctl(sock, SIOCGIFCONF, &ifc);
if (iRet != 0) {
close(sock);
return iRet;
}
int cnt = ifc.ifc_len / sizeof(struct ifreq);
//printf("ifc.size=%d\n", cnt);
if (cnt == 0) {
close(sock);
return -20;
}
struct ifreq ifr;
ifcs.clear();
ifconfig_t tmp;
for (int i = 0; i < cnt; ++i) {
// name
strcpy(ifr.ifr_name, ifc.ifc_req[i].ifr_name);
//printf("name: %s\n", ifr.ifr_name);
strncpy(tmp.name, ifr.ifr_name, sizeof(tmp.name));
// flags
//iRet = ioctl(sock, SIOCGIFFLAGS, &ifr);
//short flags = ifr.ifr_flags;
// addr
iRet = ioctl(sock, SIOCGIFADDR, &ifr);
struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;
char* ip = inet_ntoa(addr->sin_addr);
//printf("ip: %s\n", ip);
strncpy(tmp.ip, ip, sizeof(tmp.ip));
// netmask
iRet = ioctl(sock, SIOCGIFNETMASK, &ifr);
addr = (struct sockaddr_in*)&ifr.ifr_netmask;
char* netmask = inet_ntoa(addr->sin_addr);
//printf("netmask: %s\n", netmask);
strncpy(tmp.mask, netmask, sizeof(tmp.mask));
// broadaddr
iRet = ioctl(sock, SIOCGIFBRDADDR, &ifr);
addr = (struct sockaddr_in*)&ifr.ifr_broadaddr;
char* broadaddr = inet_ntoa(addr->sin_addr);
//printf("broadaddr: %s\n", broadaddr);
strncpy(tmp.broadcast, broadaddr, sizeof(tmp.broadcast));
// hwaddr
iRet = ioctl(sock, SIOCGIFHWADDR, &ifr);
snprintf(tmp.mac, sizeof(tmp.mac), "%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned char)ifr.ifr_hwaddr.sa_data[0],
(unsigned char)ifr.ifr_hwaddr.sa_data[1],
(unsigned char)ifr.ifr_hwaddr.sa_data[2],
(unsigned char)ifr.ifr_hwaddr.sa_data[3],
(unsigned char)ifr.ifr_hwaddr.sa_data[4],
(unsigned char)ifr.ifr_hwaddr.sa_data[5]);
//printf("mac: %s\n", tmp.mac);
//printf("\n");
if (strcmp(tmp.ip, "0.0.0.0") == 0 ||
strcmp(tmp.ip, "127.0.0.1") == 0 ||
strcmp(tmp.mac, "00:00:00:00:00:00") == 0) {
continue;
}
ifcs.push_back(tmp);
}
close(sock);
return 0;
}
#elif defined(OS_WIN)
#include <winsock2.h>
#include <windows.h>
#include <ws2ipdef.h>
#include <iphlpapi.h>
int ifconfig(std::vector<ifconfig_t>& ifcs) {
PIP_ADAPTER_ADDRESSES pAddrs = NULL;
ULONG buflen = 0;
GetAdaptersAddresses(AF_INET, 0, NULL, pAddrs, &buflen);
pAddrs = (PIP_ADAPTER_ADDRESSES)malloc(buflen);
GetAdaptersAddresses(AF_INET, 0, NULL, pAddrs, &buflen);
PIP_ADAPTER_INFO pInfos = NULL;
buflen = 0;
GetAdaptersInfo(pInfos, &buflen);
pInfos = (PIP_ADAPTER_INFO)malloc(buflen);
GetAdaptersInfo(pInfos, &buflen);
ifconfig_t ifc;
std::vector<ifconfig_t> tmp_ifcs;
PIP_ADAPTER_ADDRESSES pAddr = pAddrs;
char mac[32] = {'\0'};
while (pAddr) {
snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
pAddr->PhysicalAddress[0],
pAddr->PhysicalAddress[1],
pAddr->PhysicalAddress[2],
pAddr->PhysicalAddress[3],
pAddr->PhysicalAddress[4],
pAddr->PhysicalAddress[5]);
memset(&ifc, 0, sizeof(ifc));
strncpy(ifc.name, pAddr->AdapterName, sizeof(ifc.name));
strncpy(ifc.ip, "0.0.0.0", sizeof(ifc.ip));
strncpy(ifc.mask, "255.255.255.255", sizeof(ifc.mask));
strncpy(ifc.mac, mac, sizeof(ifc.mac));
tmp_ifcs.push_back(ifc);
pAddr = pAddr->Next;
}
PIP_ADAPTER_INFO pInfo = pInfos;
while (pInfo) {
for (auto& item : tmp_ifcs) {
if (strcmp(item.name, pInfo->AdapterName) == 0) {
// description more friendly
strncpy(item.name, pInfo->Description, sizeof(item.name));
strncpy(item.ip, pInfo->IpAddressList.IpAddress.String, sizeof(item.ip));
strncpy(item.mask, pInfo->IpAddressList.IpMask.String, sizeof(item.mask));
}
}
pInfo = pInfo->Next;
}
free(pAddrs);
free(pInfos);
// filter
ifcs.clear();
for (auto& item : tmp_ifcs) {
if (strcmp(item.ip, "0.0.0.0") == 0 ||
strcmp(item.ip, "127.0.0.1") == 0 ||
strcmp(item.mac, "00:00:00:00:00:00") == 0) {
continue;
}
ifcs.push_back(item);
}
return 0;
}
#elif defined(OS_MAC)
#include <ifaddrs.h>
#include <net/if_dl.h>
int ifconfig(std::vector<ifconfig_t>& ifcs) {
struct ifaddrs *ifas, *ifap;
int ret = getifaddrs(&ifas);
if (ret != 0) return ret;
ifconfig_s tmp;
for (ifap = ifas; ifap != NULL; ifap = ifap->ifa_next) {
if (ifap->ifa_addr->sa_family == AF_INET) {
// ipv4
struct sockaddr_in* addr = (struct sockaddr_in*)ifap->ifa_addr;
char* ip = inet_ntoa(addr->sin_addr);
// filter
if (strcmp(ip, "0.0.0.0") == 0 || strcmp(ip, "127.0.0.1") == 0) {
continue;
}
memset(&tmp, 0, sizeof(tmp));
strncpy(tmp.name, ifap->ifa_name, sizeof(tmp.name));
strncpy(tmp.ip, ip, sizeof(tmp.ip));
// netmask
addr = (struct sockaddr_in*)ifap->ifa_netmask;
char* netmask = inet_ntoa(addr->sin_addr);
strncpy(tmp.mask, netmask, sizeof(tmp.mask));
// broadaddr
addr = (struct sockaddr_in*)ifap->ifa_broadaddr;
char* broadaddr = inet_ntoa(addr->sin_addr);
strncpy(tmp.broadcast, broadaddr, sizeof(tmp.broadcast));
// push_back
ifcs.push_back(tmp);
}
}
for (ifap = ifas; ifap != NULL; ifap = ifap->ifa_next) {
if (ifap->ifa_addr->sa_family == AF_LINK) {
// hwaddr
for (auto iter = ifcs.begin(); iter != ifcs.end(); ++iter) {
if (strcmp(iter->name, ifap->ifa_name) == 0) {
struct sockaddr_dl* addr = (struct sockaddr_dl*)ifap->ifa_addr;
unsigned char* pmac = (unsigned char*)LLADDR(addr);
snprintf(iter->mac, sizeof(iter->mac), "%02x:%02x:%02x:%02x:%02x:%02x",
pmac[0], pmac[1], pmac[2], pmac[3], pmac[4], pmac[5]);
// filter
if (strcmp(iter->mac, "00:00:00:00:00:00") == 0) {
ifcs.erase(iter);
}
break;
}
}
}
}
freeifaddrs(ifas);
return 0;
}
#else
int ifconfig(std::vector<ifconfig_t>& ifcs) {
return -10; // unimplemented
}
#endif

36
third_party/libhv/cpputil/ifconfig.h vendored Executable file
View File

@@ -0,0 +1,36 @@
#ifndef HV_IFCONFIG_H_
#define HV_IFCONFIG_H_
#include <vector>
#include "hexport.h"
#ifdef _MSC_VER
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#endif
typedef struct ifconfig_s {
char name[128];
char ip[16];
char mask[16];
char broadcast[16];
char mac[20];
} ifconfig_t;
/*
* @test
std::vector<ifconfig_t> ifcs;
ifconfig(ifcs);
for (auto& item : ifcs) {
printf("%s\nip: %s\nmask: %s\nbroadcast: %s\nmac: %s\n\n",
item.name,
item.ip,
item.mask,
item.broadcast,
item.mac);
}
*/
HV_EXPORT int ifconfig(std::vector<ifconfig_t>& ifcs);
#endif // HV_IFCONFIG_H_

390
third_party/libhv/cpputil/iniparser.cpp vendored Executable file
View File

@@ -0,0 +1,390 @@
#include "iniparser.h"
#include <sstream>
#include "hdef.h"
#include "herr.h"
#include "hstring.h"
#include "hfile.h"
#include "hbase.h"
using namespace hv;
/**********************************
# div
[section]
key = value # span
# div
***********************************/
class IniNode {
public:
enum Type {
INI_NODE_TYPE_UNKNOWN,
INI_NODE_TYPE_ROOT,
INI_NODE_TYPE_SECTION,
INI_NODE_TYPE_KEY_VALUE,
INI_NODE_TYPE_DIV,
INI_NODE_TYPE_SPAN,
} type;
std::string label; // section|key|comment
std::string value;
std::list<IniNode*> children;
virtual ~IniNode() {
for (auto pNode : children) {
if (pNode) {
delete pNode;
}
}
children.clear();
}
void Add(IniNode* pNode) {
children.push_back(pNode);
}
void Del(IniNode* pNode) {
for (auto iter = children.begin(); iter != children.end(); ++iter) {
if ((*iter) == pNode) {
delete (*iter);
children.erase(iter);
return;
}
}
}
IniNode* Get(const std::string& label, Type type = INI_NODE_TYPE_KEY_VALUE) {
for (auto pNode : children) {
if (pNode->type == type && pNode->label == label) {
return pNode;
}
}
return NULL;
}
};
class IniSection : public IniNode {
public:
IniSection() : IniNode(), section(label) {
type = INI_NODE_TYPE_SECTION;
}
std::string &section;
};
class IniKeyValue : public IniNode {
public:
IniKeyValue() : IniNode(), key(label) {
type = INI_NODE_TYPE_KEY_VALUE;
}
std::string &key;
};
class IniComment : public IniNode {
public:
IniComment() : IniNode(), comment(label) {
}
std::string &comment;
};
IniParser::IniParser() {
_comment = DEFAULT_INI_COMMENT;
_delim = DEFAULT_INI_DELIM;
root_ = NULL;
}
IniParser::~IniParser() {
Unload();
}
int IniParser::Unload() {
SAFE_DELETE(root_);
return 0;
}
int IniParser::Reload() {
return LoadFromFile(_filepath.c_str());
}
int IniParser::LoadFromFile(const char* filepath) {
_filepath = filepath;
HFile file;
if (file.open(filepath, "r") != 0) {
return ERR_OPEN_FILE;
}
std::string str;
file.readall(str);
const char* c_str = str.c_str();
unsigned char utf8_bom[3] = { 0xEF, 0xBB, 0xBF };
if (str.size() >= 3 && memcmp(c_str, utf8_bom, 3) == 0) {
c_str += 3;
}
return LoadFromMem(c_str);
}
int IniParser::LoadFromMem(const char* data) {
Unload();
root_ = new IniNode;
root_->type = IniNode::INI_NODE_TYPE_ROOT;
std::stringstream ss;
ss << data;
std::string strLine;
int line = 0;
std::string::size_type pos;
std::string content, comment, strDiv;
IniNode* pScopeNode = root_;
IniNode* pNewNode = NULL;
while (std::getline(ss, strLine)) {
++line;
content = ltrim(strLine);
if (content.length() == 0) {
// blank line
strDiv += '\n';
continue;
}
// trim_comment
comment = "";
pos = content.find_first_of(_comment);
if (pos != std::string::npos) {
comment = content.substr(pos);
content = content.substr(0, pos);
}
content = rtrim(content);
if (content.length() == 0) {
strDiv += strLine;
strDiv += '\n';
continue;
} else if (strDiv.length() != 0) {
IniNode* pNode = new IniNode;
pNode->type = IniNode::INI_NODE_TYPE_DIV;
pNode->label = strDiv;
pScopeNode->Add(pNode);
strDiv = "";
}
if (content[0] == '[') {
if (content[content.length()-1] == ']') {
// section
content = trim(content.substr(1, content.length()-2));
pNewNode = new IniNode;
pNewNode->type = IniNode::INI_NODE_TYPE_SECTION;
pNewNode->label = content;
root_->Add(pNewNode);
pScopeNode = pNewNode;
} else {
// hlogw("format error, line:%d", line);
continue; // ignore
}
} else {
pos = content.find_first_of(_delim);
if (pos != std::string::npos) {
// key-value
pNewNode = new IniNode;
pNewNode->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
pNewNode->label = trim(content.substr(0, pos));
pNewNode->value = trim(content.substr(pos+_delim.length()));
pScopeNode->Add(pNewNode);
} else {
// hlogw("format error, line:%d", line);
continue; // ignore
}
}
if (comment.length() != 0) {
// tail_comment
IniNode* pNode = new IniNode;
pNode->type = IniNode::INI_NODE_TYPE_SPAN;
pNode->label = comment;
pNewNode->Add(pNode);
comment = "";
}
}
// file end comment
if (strDiv.length() != 0) {
IniNode* pNode = new IniNode;
pNode->type = IniNode::INI_NODE_TYPE_DIV;
pNode->label = strDiv;
root_->Add(pNode);
}
return 0;
}
void IniParser::DumpString(IniNode* pNode, std::string& str) {
if (pNode == NULL) return;
if (pNode->type != IniNode::INI_NODE_TYPE_SPAN) {
if (str.length() > 0 && str[str.length()-1] != '\n') {
str += '\n';
}
}
switch (pNode->type) {
case IniNode::INI_NODE_TYPE_SECTION: {
str += '[';
str += pNode->label;
str += ']';
}
break;
case IniNode::INI_NODE_TYPE_KEY_VALUE: {
str += asprintf("%s %s %s", pNode->label.c_str(), _delim.c_str(), pNode->value.c_str());
}
break;
case IniNode::INI_NODE_TYPE_DIV: {
str += pNode->label;
}
break;
case IniNode::INI_NODE_TYPE_SPAN: {
str += '\t';
str += pNode->label;
}
break;
default:
break;
}
for (auto p : pNode->children) {
DumpString(p, str);
}
}
std::string IniParser::DumpString() {
std::string str;
DumpString(root_, str);
return str;
}
int IniParser::Save() {
return SaveAs(_filepath.c_str());
}
int IniParser::SaveAs(const char* filepath) {
std::string str = DumpString();
if (str.length() == 0) {
return 0;
}
HFile file;
if (file.open(filepath, "w") != 0) {
return ERR_SAVE_FILE;
}
file.write(str.c_str(), str.length());
return 0;
}
std::list<std::string> IniParser::GetSections() {
std::list<std::string> ret;
if (root_ == NULL) return ret;
for (auto pNode : root_->children) {
if (pNode->type == IniNode::INI_NODE_TYPE_SECTION) {
ret.push_back(pNode->label);
}
}
return ret;
}
std::list<std::string> IniParser::GetKeys(const std::string& section) {
std::list<std::string> ret;
if (root_ == NULL) return ret;
IniNode* pSection = root_;
if (section.length() != 0) {
pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
if (pSection == NULL) return ret;
}
for (auto pNode : pSection->children) {
if (pNode->type == IniNode::INI_NODE_TYPE_KEY_VALUE) {
ret.push_back(pNode->label);
}
}
return ret;
}
std::string IniParser::GetValue(const std::string& key, const std::string& section) {
if (root_ == NULL) return "";
IniNode* pSection = root_;
if (section.length() != 0) {
pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
if (pSection == NULL) return "";
}
IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
if (pKV == NULL) return "";
return pKV->value;
}
void IniParser::SetValue(const std::string& key, const std::string& value, const std::string& section) {
if (root_ == NULL) {
root_ = new IniNode;
}
IniNode* pSection = root_;
if (section.length() != 0) {
pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
if (pSection == NULL) {
pSection = new IniNode;
pSection->type = IniNode::INI_NODE_TYPE_SECTION;
pSection->label = section;
root_->Add(pSection);
}
}
IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
if (pKV == NULL) {
pKV = new IniNode;
pKV->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
pKV->label = key;
pSection->Add(pKV);
}
pKV->value = value;
}
template<>
HV_EXPORT bool IniParser::Get(const std::string& key, const std::string& section, bool defvalue) {
std::string str = GetValue(key, section);
return str.empty() ? defvalue : hv_getboolean(str.c_str());
}
template<>
HV_EXPORT int IniParser::Get(const std::string& key, const std::string& section, int defvalue) {
std::string str = GetValue(key, section);
return str.empty() ? defvalue : atoi(str.c_str());
}
template<>
HV_EXPORT float IniParser::Get(const std::string& key, const std::string& section, float defvalue) {
std::string str = GetValue(key, section);
return str.empty() ? defvalue : atof(str.c_str());
}
template<>
HV_EXPORT void IniParser::Set(const std::string& key, const bool& value, const std::string& section) {
SetValue(key, value ? "true" : "false", section);
}
template<>
HV_EXPORT void IniParser::Set(const std::string& key, const int& value, const std::string& section) {
SetValue(key, asprintf("%d", value), section);
}
template<>
HV_EXPORT void IniParser::Set(const std::string& key, const float& value, const std::string& section) {
SetValue(key, asprintf("%f", value), section);
}

53
third_party/libhv/cpputil/iniparser.h vendored Executable file
View File

@@ -0,0 +1,53 @@
#ifndef HV_INI_PARSER_H_
#define HV_INI_PARSER_H_
#include <string>
#include <list>
#include "hexport.h"
#define DEFAULT_INI_COMMENT "#"
#define DEFAULT_INI_DELIM "="
// fwd
class IniNode;
class HV_EXPORT IniParser {
public:
IniParser();
~IniParser();
int LoadFromFile(const char* filepath);
int LoadFromMem(const char* data);
int Unload();
int Reload();
std::string DumpString();
int Save();
int SaveAs(const char* filepath);
std::list<std::string> GetSections();
std::list<std::string> GetKeys(const std::string& section = "");
std::string GetValue(const std::string& key, const std::string& section = "");
void SetValue(const std::string& key, const std::string& value, const std::string& section = "");
// T = [bool, int, float]
template<typename T>
T Get(const std::string& key, const std::string& section = "", T defvalue = 0);
// T = [bool, int, float]
template<typename T>
void Set(const std::string& key, const T& value, const std::string& section = "");
protected:
void DumpString(IniNode* pNode, std::string& str);
public:
std::string _comment;
std::string _delim;
std::string _filepath;
private:
IniNode* root_;
};
#endif // HV_INI_PARSER_H_

25447
third_party/libhv/cpputil/json.hpp vendored Executable file

File diff suppressed because it is too large Load Diff

36
third_party/libhv/cpputil/singleton.h vendored Executable file
View File

@@ -0,0 +1,36 @@
#ifndef HV_SINGLETON_H_
#define HV_SINGLETON_H_
#include <mutex>
#define DISABLE_COPY(Class) \
Class(const Class&) = delete; \
Class& operator=(const Class&) = delete;
#define SINGLETON_DECL(Class) \
public: \
static Class* instance(); \
static void exitInstance(); \
private: \
DISABLE_COPY(Class) \
static Class* s_pInstance; \
static std::once_flag s_initFlag; \
static std::mutex s_mutex;
#define SINGLETON_IMPL(Class) \
Class* Class::s_pInstance = NULL; \
std::once_flag Class::s_initFlag; \
std::mutex Class::s_mutex; \
Class* Class::instance() { \
std::call_once(s_initFlag, []() {s_pInstance = new Class;}); \
return s_pInstance; \
} \
void Class::exitInstance() { \
std::lock_guard<std::mutex> lock(s_mutex); \
if (s_pInstance) { \
delete s_pInstance; \
s_pInstance = nullptr; \
} \
}
#endif // HV_SINGLETON_H_