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

118
third_party/libhv/unittest/CMakeLists.txt vendored Executable file
View File

@@ -0,0 +1,118 @@
add_definitions(-DHV_SOURCE=1)
# ------base------
add_executable(hbase_test hbase_test.c ../base/hbase.c)
target_include_directories(hbase_test PRIVATE .. ../base)
add_executable(mkdir_p mkdir_test.c ../base/hbase.c)
target_include_directories(mkdir_p PRIVATE .. ../base)
add_executable(rmdir_p rmdir_test.c ../base/hbase.c)
target_include_directories(rmdir_p PRIVATE .. ../base)
add_executable(date date_test.c ../base/htime.c)
target_include_directories(date PRIVATE .. ../base)
add_executable(hatomic_test hatomic_test.c)
target_include_directories(hatomic_test PRIVATE .. ../base)
target_link_libraries(hatomic_test -lpthread)
add_executable(hthread_test hthread_test.cpp)
target_include_directories(hthread_test PRIVATE .. ../base)
target_link_libraries(hthread_test -lpthread)
add_executable(hmutex_test hmutex_test.c ../base/htime.c)
target_include_directories(hmutex_test PRIVATE .. ../base)
target_link_libraries(hmutex_test -lpthread)
add_executable(connect_test connect_test.c ../base/hsocket.c ../base/htime.c)
target_include_directories(connect_test PRIVATE .. ../base)
add_executable(socketpair_test socketpair_test.c ../base/hsocket.c)
target_include_directories(socketpair_test PRIVATE .. ../base)
# ------util------
add_executable(base64 base64_test.c ../util/base64.c)
target_include_directories(base64 PRIVATE .. ../util)
add_executable(md5 md5_test.c ../util/md5.c)
target_include_directories(md5 PRIVATE .. ../util)
add_executable(sha1 sha1_test.c ../util/sha1.c)
target_include_directories(sha1 PRIVATE .. ../util)
# ------cpputil------
add_executable(hstring_test hstring_test.cpp ../cpputil/hstring.cpp)
target_include_directories(hstring_test PRIVATE .. ../base ../cpputil)
add_executable(hpath_test hpath_test.cpp ../cpputil/hpath.cpp)
target_include_directories(hpath_test PRIVATE .. ../base ../cpputil)
add_executable(hurl_test hurl_test.cpp ../cpputil/hurl.cpp ../base/hbase.c)
target_include_directories(hurl_test PRIVATE .. ../base ../cpputil)
add_executable(ls listdir_test.cpp ../cpputil/hdir.cpp)
target_include_directories(ls PRIVATE .. ../base ../cpputil)
add_executable(ifconfig ifconfig_test.cpp ../cpputil/ifconfig.cpp)
target_include_directories(ifconfig PRIVATE .. ../base ../cpputil)
add_executable(defer_test defer_test.cpp)
target_include_directories(defer_test PRIVATE .. ../base ../cpputil)
add_executable(synchronized_test synchronized_test.cpp)
target_include_directories(synchronized_test PRIVATE .. ../base ../cpputil)
target_link_libraries(synchronized_test -lpthread)
add_executable(threadpool_test threadpool_test.cpp)
target_include_directories(threadpool_test PRIVATE .. ../base ../cpputil)
target_link_libraries(threadpool_test -lpthread)
add_executable(objectpool_test objectpool_test.cpp)
target_include_directories(objectpool_test PRIVATE .. ../base ../cpputil)
target_link_libraries(objectpool_test -lpthread)
# ------protocol------
add_executable(nslookup nslookup_test.c ../protocol/dns.c)
target_include_directories(nslookup PRIVATE .. ../base ../protocol)
add_executable(ping ping_test.c ../protocol/icmp.c ../base/hsocket.c ../base/htime.c)
target_compile_definitions(ping PRIVATE -DPRINT_DEBUG)
target_include_directories(ping PRIVATE .. ../base ../protocol)
add_executable(ftp ftp_test.c ../protocol/ftp.c ../base/hsocket.c)
target_include_directories(ftp PRIVATE .. ../base ../protocol)
add_executable(sendmail sendmail_test.c ../protocol/smtp.c ../base/hsocket.c ../util/base64.c)
target_include_directories(sendmail PRIVATE .. ../base ../protocol ../util)
if(UNIX)
add_executable(webbench webbench.c)
endif()
add_custom_target(unittest DEPENDS
mkdir_p
rmdir_p
date
hatomic_test
hthread_test
hmutex_test
connect_test
socketpair_test
base64
md5
sha1
hstring_test
hpath_test
hurl_test
ls
ifconfig
defer_test
synchronized_test
threadpool_test
objectpool_test
nslookup
ping
ftp
sendmail
)

118
third_party/libhv/unittest/base64_test.c vendored Executable file
View File

@@ -0,0 +1,118 @@
/*
* @build: gcc -o bin/base64 unittest/base64_test.c util/base64.c -I. -Iutil
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "base64.h"
static void test() {
unsigned char in[] = "0123456789";
// test encode
int encoded_size = BASE64_ENCODE_OUT_SIZE(10);
char* encoded = (char*)malloc(encoded_size + 1);
encoded_size = hv_base64_encode(in, 10, encoded);
encoded[encoded_size] = '\0';
assert(strcmp(encoded, "MDEyMzQ1Njc4OQ==") == 0);
// test decode
int decoded_size = BASE64_DECODE_OUT_SIZE(encoded_size);
unsigned char* decoded = (unsigned char*)malloc(decoded_size);
decoded_size = hv_base64_decode(encoded, encoded_size, decoded);
assert(decoded_size == 10 && memcmp(in, decoded, decoded_size) == 0);
free(encoded);
free(decoded);
}
int main(int argc, char* argv[]) {
test();
if (argc < 3) {
printf("Usage: base64 infile outfile\n");
printf(" base64 -d infile outfile\n");
return -10;
}
else if (argc == 3) {
// encode file
const char* infile = argv[1];
const char* outfile = argv[2];
FILE* infp = fopen(infile, "rb");
if (infp == NULL) {
printf("Open file '%s' failed!\n", infile);
return -20;
}
fseek(infp, 0, SEEK_END);
long filesize = ftell(infp);
// printf("filesize=%ld\n", filesize);
fseek(infp, 0, SEEK_SET);
unsigned char* filebuf = (unsigned char*)malloc(filesize);
size_t nread = fread(filebuf, 1, filesize, infp);
assert(nread == filesize);
int encoded_size = BASE64_ENCODE_OUT_SIZE(filesize);
char* encoded = (char*)malloc(encoded_size + 1);
encoded_size = hv_base64_encode(filebuf, filesize, encoded);
encoded[encoded_size] = '\0';
FILE* outfp = fopen(outfile, "w");
if (outfp == NULL) {
printf("Save file '%s' failed!\n", infile);
return -20;
}
size_t nwrite = fwrite(encoded, 1, encoded_size, outfp);
assert(nwrite == encoded_size);
free(filebuf);
free(encoded);
fclose(infp);
fclose(outfp);
}
else if (argc == 4) {
const char* flags = argv[1];
if (flags[0] == '-' && flags[1] == 'd') {
// decode file
const char* infile = argv[2];
const char* outfile = argv[3];
FILE* infp = fopen(infile, "r");
if (infp == NULL) {
printf("Open file '%s' failed!\n", infile);
return -20;
}
fseek(infp, 0, SEEK_END);
long filesize = ftell(infp);
// printf("filesize=%ld\n", filesize);
fseek(infp, 0, SEEK_SET);
char* filebuf = (char*)malloc(filesize);
size_t nread = fread(filebuf, 1, filesize, infp);
assert(nread == filesize);
int decoded_size = BASE64_DECODE_OUT_SIZE(filesize);
unsigned char* decoded = (unsigned char*)malloc(decoded_size);
decoded_size = hv_base64_decode(filebuf, filesize, decoded);
FILE* outfp = fopen(outfile, "wb");
if (outfp == NULL) {
printf("Save file '%s' failed!\n", infile);
return -20;
}
size_t nwrite = fwrite(decoded, 1, decoded_size, outfp);
assert(nwrite == decoded_size);
free(filebuf);
free(decoded);
fclose(infp);
fclose(outfp);
}
else {
printf("Unrecognized flags '%s'\n", flags);
return -40;
}
}
return 0;
}

29
third_party/libhv/unittest/connect_test.c vendored Executable file
View File

@@ -0,0 +1,29 @@
#include "hsocket.h"
#include "htime.h"
int main(int argc, char* argv[]) {
if (argc < 3) {
printf("Usage: cmd ip port\n");
return -10;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
unsigned int start_time = gettick_ms();
int ret = ConnectNonblock(ip, port);
unsigned int end_time = gettick_ms();
printf("ConnectNonblock[%s:%d] retval=%d cost=%ums\n", ip, port, ret, end_time-start_time);
start_time = gettick_ms();
ret = ConnectTimeout(ip, port, 3000);
end_time = gettick_ms();
printf("ConnectTimeout[%s:%d] retval=%d cost=%ums\n", ip, port, ret, end_time-start_time);
start_time = gettick_ms();
ret = Connect(ip, port, 0);
end_time = gettick_ms();
printf("ConnectBlock[%s:%d] retval=%d cost=%ums\n", ip, port, ret, end_time-start_time);
return 0;
}

17
third_party/libhv/unittest/date_test.c vendored Executable file
View File

@@ -0,0 +1,17 @@
#include "htime.h"
int main(int argc, char* argv[]) {
datetime_t dt = datetime_now();
char buf1[DATETIME_FMT_BUFLEN];
datetime_fmt(&dt, buf1);
puts(buf1);
datetime_fmt_iso(&dt, buf1);
puts(buf1);
time_t ts = datetime_mktime(&dt);
char buf2[GMTIME_FMT_BUFLEN];
gmtime_fmt(ts, buf2);
puts(buf2);
return 0;
}

19
third_party/libhv/unittest/defer_test.cpp vendored Executable file
View File

@@ -0,0 +1,19 @@
#include <stdio.h>
#include "hscope.h"
int main() {
defer (
printf("1\n");
printf("2\n");
)
defer (
printf("3\n");
printf("4\n");
)
defer(printf("hello\n");)
return 0;
}

88
third_party/libhv/unittest/ftp_test.c vendored Executable file
View File

@@ -0,0 +1,88 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ftp.h"
void print_help() {
printf("Usage:\n\
help\n\
login <username> <password>\n\
download <remote_filepath> <local_filepath>\n\
upload <local_filepath> <remote_filepath>\n\
quit\n");
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: ftp host [port]\n");
return 0;
}
const char* host = argv[1];
int port = FTP_COMMAND_PORT;
if (argc >= 3) {
port = atoi(argv[2]);
}
int ret = 0;
ftp_handle_t hftp;
ret = ftp_connect(&hftp, host, port);
if (ret != 0) {
printf("ftp connect failed!\n");
return ret;
}
print_help();
char cmd[256] = {0};
char param1[256] = {0};
char param2[256] = {0};
while (1) {
printf("> ");
scanf("%s", cmd);
if (strncmp(cmd, "help", 4) == 0) {
print_help();
}
else if (strncmp(cmd, "login", 5) == 0) {
scanf("%s", param1);
scanf("%s", param2);
//printf("cmd=%s param1=%s param2=%s\n", cmd, param1, param2);
const char* username = param1;
const char* password = param2;
ret = ftp_login(&hftp, username, password);
printf("%s", hftp.recvbuf);
if (ret != 0) break;
}
else if (strncmp(cmd, "upload", 6) == 0) {
scanf("%s", param1);
scanf("%s", param2);
//printf("cmd=%s param1=%s param2=%s\n", cmd, param1, param2);
const char* localfile = param1;
const char* remotefile = param2;
ret = ftp_upload(&hftp, localfile, remotefile);
printf("%s", hftp.recvbuf);
if (ret != 0) break;
}
else if (strncmp(cmd, "download", 8) == 0) {
scanf("%s", param1);
scanf("%s", param2);
//printf("cmd=%s param1=%s param2=%s\n", cmd, param1, param2);
const char* remotefile = param1;
const char* localfile = param2;
ret = ftp_download(&hftp, remotefile, localfile);
printf("%s", hftp.recvbuf);
if (ret != 0) break;
}
else if (strncmp(cmd, "quit", 4) == 0) {
break;
}
else {
scanf("%s", param1);
//printf("cmd=%s param=%s\n", cmd, param1);
ret = ftp_exec(&hftp, cmd, param1);
printf("%s", hftp.recvbuf);
}
}
printf("QUIT\n");
ftp_quit(&hftp);
printf("%s", hftp.recvbuf);
return 0;
}

39
third_party/libhv/unittest/hatomic_test.c vendored Executable file
View File

@@ -0,0 +1,39 @@
#include <stdio.h>
#include "hatomic.h"
#include "hthread.h"
hatomic_flag_t flag = HATOMIC_FLAG_INIT;
hatomic_t cnt = HATOMIC_VAR_INIT(0);
HTHREAD_ROUTINE(test_hatomic_flag) {
if (!hatomic_flag_test_and_set(&flag)) {
printf("tid=%ld flag 0=>1\n", hv_gettid());
}
else {
printf("tid=%ld flag=1\n", hv_gettid());
}
return 0;
}
HTHREAD_ROUTINE(test_hatomic) {
for (int i = 0; i < 10; ++i) {
long n = hatomic_inc(&cnt);
printf("tid=%ld cnt=%ld\n", hv_gettid(), n);
hv_delay(1);
}
return 0;
}
int main() {
for (int i = 0; i < 10; ++i) {
hthread_create(test_hatomic_flag, NULL);
}
for (int i = 0; i < 10; ++i) {
hthread_create(test_hatomic, NULL);
}
hv_delay(1000);
return 0;
}

39
third_party/libhv/unittest/hatomic_test.cpp vendored Executable file
View File

@@ -0,0 +1,39 @@
#include <stdio.h>
#include "hatomic.h"
#include "hthread.h"
hatomic_flag_t flag = HATOMIC_FLAG_INIT;
hatomic_t cnt = HATOMIC_VAR_INIT(0);
HTHREAD_ROUTINE(test_hatomic_flag) {
if (!hatomic_flag_test_and_set(&flag)) {
printf("tid=%ld flag 0=>1\n", hv_gettid());
}
else {
printf("tid=%ld flag=1\n", hv_gettid());
}
return 0;
}
HTHREAD_ROUTINE(test_hatomic) {
for (int i = 0; i < 10; ++i) {
long n = hatomic_inc(&cnt);
printf("tid=%ld cnt=%ld\n", hv_gettid(), n);
hv_delay(1);
}
return 0;
}
int main() {
for (int i = 0; i < 10; ++i) {
hthread_create(test_hatomic_flag, NULL);
}
for (int i = 0; i < 10; ++i) {
hthread_create(test_hatomic, NULL);
}
hv_delay(1000);
return 0;
}

114
third_party/libhv/unittest/hbase_test.c vendored Executable file
View File

@@ -0,0 +1,114 @@
#include "hbase.h"
int main(int argc, char* argv[]) {
char buf[16] = {0};
printf("hv_rand(10, 99) -> %d\n", hv_rand(10, 99));
printf("hv_random_string(buf, 10) -> %s\n", hv_random_string(buf, 10));
assert(hv_getboolean("1"));
assert(hv_getboolean("yes"));
assert(hv_wildcard_match("www.example.com", "www.example.com"));
assert(hv_wildcard_match("www.example.com", "*.example.com"));
assert(hv_wildcard_match("www.example.com", "www.*.com"));
assert(hv_wildcard_match("www.example.com", "www.example.*"));
assert(hv_parse_size("256") == 256);
assert(hv_parse_size("1K") == 1024);
assert(hv_parse_size("1G2M3K4B") ==
1 * 1024 * 1024 * 1024 +
2 * 1024 * 1024 +
3 * 1024 +
4);
assert(hv_parse_time("30") == 30);
assert(hv_parse_time("1m") == 60);
assert(hv_parse_time("1d2h3m4s") ==
1 * 24 * 60 * 60 +
2 * 60 * 60 +
3 * 60 +
4);
const char* test_urls[] = {
"http://user:pswd@www.example.com:80/path?query#fragment",
"http://user:pswd@www.example.com/path?query#fragment",
"http://www.example.com/path?query#fragment",
"http://www.example.com/path?query",
"http://www.example.com/path",
"www.example.com/path",
"/path",
};
hurl_t stURL;
for (int i = 0; i < ARRAY_SIZE(test_urls); ++i) {
const char* strURL = test_urls[i];
printf("%s =>\n", strURL);
hv_parse_url(&stURL, strURL);
assert(stURL.port == 80);
// scheme://
if (stURL.fields[HV_URL_SCHEME].len > 0) {
const char* scheme = strURL + stURL.fields[HV_URL_SCHEME].off;
int len = stURL.fields[HV_URL_SCHEME].len;
assert(len == 4);
assert(strncmp(scheme, "http", len) == 0);
printf("%.*s://", len, scheme);
}
// user:pswd@
if (stURL.fields[HV_URL_USERNAME].len > 0) {
const char* user = strURL + stURL.fields[HV_URL_USERNAME].off;
int len = stURL.fields[HV_URL_USERNAME].len;
assert(len == 4);
assert(strncmp(user, "user", len) == 0);
printf("%.*s", len, user);
if (stURL.fields[HV_URL_PASSWORD].len > 0) {
const char* pswd = strURL + stURL.fields[HV_URL_PASSWORD].off;
int len = stURL.fields[HV_URL_PASSWORD].len;
assert(len == 4);
assert(strncmp(pswd, "pswd", len) == 0);
printf(":%.*s", len, pswd);
}
printf("@");
}
// host:port
if (stURL.fields[HV_URL_HOST].len > 0) {
const char* host = strURL + stURL.fields[HV_URL_HOST].off;
int len = stURL.fields[HV_URL_HOST].len;
assert(len == strlen("www.example.com"));
assert(strncmp(host, "www.example.com", len) == 0);
printf("%.*s", len, host);
if (stURL.fields[HV_URL_PORT].len > 0) {
const char* port = strURL + stURL.fields[HV_URL_PORT].off;
int len = stURL.fields[HV_URL_PORT].len;
assert(len == 2);
assert(strncmp(port, "80", len) == 0);
printf(":%.*s", len, port);
}
}
// /path
if (stURL.fields[HV_URL_PATH].len > 0) {
const char* path = strURL + stURL.fields[HV_URL_PATH].off;
int len = stURL.fields[HV_URL_PATH].len;
assert(len == 5);
assert(strncmp(path, "/path", len) == 0);
printf("%.*s", len, path);
}
// ?query
if (stURL.fields[HV_URL_QUERY].len > 0) {
const char* query = strURL + stURL.fields[HV_URL_QUERY].off;
int len = stURL.fields[HV_URL_QUERY].len;
assert(len == 5);
assert(strncmp(query, "query", len) == 0);
printf("?%.*s", len, query);
}
// #fragment
if (stURL.fields[HV_URL_FRAGMENT].len > 0) {
const char* fragment = strURL + stURL.fields[HV_URL_FRAGMENT].off;
int len = stURL.fields[HV_URL_FRAGMENT].len;
assert(len == 8);
assert(strncmp(fragment, "fragment", len) == 0);
printf("#%.*s", len, fragment);
}
printf("\n");
}
return 0;
}

134
third_party/libhv/unittest/hmutex_test.c vendored Executable file
View File

@@ -0,0 +1,134 @@
#include "hthread.h"
#include "hmutex.h"
#include "htime.h"
void once_print() {
printf("exec once\n");
}
HTHREAD_ROUTINE(test_once) {
honce_t once = HONCE_INIT;
for (int i = 0; i < 10; ++i) {
honce(&once, once_print);
}
printf("honce test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_mutex) {
hmutex_t mutex;
hmutex_init(&mutex);
hmutex_lock(&mutex);
hmutex_unlock(&mutex);
hmutex_destroy(&mutex);
printf("hmutex test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_recursive_mutex) {
hrecursive_mutex_t mutex;
hrecursive_mutex_init(&mutex);
hrecursive_mutex_lock(&mutex);
hrecursive_mutex_lock(&mutex);
hrecursive_mutex_unlock(&mutex);
hrecursive_mutex_unlock(&mutex);
hrecursive_mutex_destroy(&mutex);
printf("hrecursive_mutex test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_spinlock) {
hspinlock_t spin;
hspinlock_init(&spin);
hspinlock_lock(&spin);
hspinlock_unlock(&spin);
hspinlock_destroy(&spin);
printf("hspinlock test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_rwlock) {
hrwlock_t rwlock;
hrwlock_init(&rwlock);
hrwlock_rdlock(&rwlock);
hrwlock_rdunlock(&rwlock);
hrwlock_wrlock(&rwlock);
hrwlock_wrunlock(&rwlock);
hrwlock_destroy(&rwlock);
printf("hrwlock test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_timed_mutex) {
htimed_mutex_t mutex;
htimed_mutex_init(&mutex);
htimed_mutex_lock(&mutex);
time_t start_time = gettick_ms();
htimed_mutex_lock_for(&mutex, 3000);
time_t end_time = gettick_ms();
printf("htimed_mutex_lock_for %zdms\n", end_time - start_time);
htimed_mutex_unlock(&mutex);
htimed_mutex_destroy(&mutex);
printf("htimed_mutex test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_condvar) {
hmutex_t mutex;
hmutex_init(&mutex);
hcondvar_t cv;
hcondvar_init(&cv);
hmutex_lock(&mutex);
hcondvar_signal(&cv);
hcondvar_broadcast(&cv);
time_t start_time = gettick_ms();
hcondvar_wait_for(&cv, &mutex, 3000);
time_t end_time = gettick_ms();
printf("hcondvar_wait_for %zdms\n", end_time - start_time);
hmutex_unlock(&mutex);
hmutex_destroy(&mutex);
hcondvar_destroy(&cv);
printf("hcondvar test OK!\n");
return 0;
}
HTHREAD_ROUTINE(test_sem) {
hsem_t sem;
hsem_init(&sem, 10);
for (int i = 0; i < 10; ++i) {
hsem_wait(&sem);
}
hsem_post(&sem);
hsem_wait(&sem);
time_t start_time = gettick_ms();
hsem_wait_for(&sem, 3000);
time_t end_time = gettick_ms();
printf("hsem_wait_for %zdms\n", end_time - start_time);
hsem_destroy(&sem);
printf("hsem test OK!\n");
return 0;
}
int main(int argc, char* argv[]) {
hthread_t thread_once = hthread_create(test_once, NULL);
hthread_t thread_mutex = hthread_create(test_mutex, NULL);
hthread_t thread_recursive_mutex = hthread_create(test_recursive_mutex, NULL);
hthread_t thread_spinlock = hthread_create(test_spinlock, NULL);
hthread_t thread_rwlock = hthread_create(test_rwlock, NULL);
hthread_t thread_timed_mutex = hthread_create(test_timed_mutex, NULL);
hthread_t thread_condvar = hthread_create(test_condvar, NULL);
hthread_t thread_sem = hthread_create(test_sem, NULL);
hthread_join(thread_once);
hthread_join(thread_mutex);
hthread_join(thread_recursive_mutex);
hthread_join(thread_spinlock);
hthread_join(thread_rwlock);
hthread_join(thread_timed_mutex);
hthread_join(thread_condvar);
hthread_join(thread_sem);
printf("hthread test OK!\n");
return 0;
}

15
third_party/libhv/unittest/hpath_test.cpp vendored Executable file
View File

@@ -0,0 +1,15 @@
#include "hpath.h"
int main(int argc, char** argv) {
std::string filepath = HPath::join("/mnt/share/image", "test.jpg");
std::string basename = HPath::basename(filepath);
std::string dirname = HPath::dirname(filepath);
std::string filename = HPath::filename(filepath);
std::string suffixname = HPath::suffixname(filepath);
printf("filepath = %s\n", filepath.c_str());
printf("basename = %s\n", basename.c_str());
printf("dirname = %s\n", dirname.c_str());
printf("filename = %s\n", filename.c_str());
printf("suffixname = %s\n", suffixname.c_str());
return 0;
}

52
third_party/libhv/unittest/hstring_test.cpp vendored Executable file
View File

@@ -0,0 +1,52 @@
#include "hstring.h"
using namespace hv;
int main(int argc, char** argv) {
std::string str1 = "a1B2*C3d4==";
std::string str2 = "a1B2*C3d4==";
println("toupper=" + toupper(str1));
println("tolower=" + tolower(str2));
std::string str3 = "abcdefg";
println("reverse=" + reverse(str3));
std::string str4 = "123456789";
printf("startswith=%d\nendswith=%d\ncontains=%d\n",
(int)startswith(str4, "123"),
(int)endswith(str4, "789"),
(int)contains(str4, "456"));
std::string str5 = asprintf("%s%d", "hello", 5);
println("asprintf=" + str5);
std::string str6("123,456,789");
StringList strlist = split(str6, ',');
println("split " + str6);
for (auto& str : strlist) {
println(str);
}
std::string str7("user=admin&pswd=123456");
hv::KeyValue kv = splitKV(str7, '&', '=');
for (auto& pair : kv) {
printf("%s=%s\n", pair.first.c_str(), pair.second.c_str());
}
std::string str8("<stdio.h>");
std::string str9 = trim_pairs(str8);
println("trim_pairs=" + str9);
std::string str10("<title>{{title}}</title>");
std::string str11 = replace(str10, "{{title}}", "Home");
println("replace=" + str11);
NetAddr addr1("0.0.0.0:8080");
println(addr1.to_string());
NetAddr addr2("[::0]:8080");
println(addr2.to_string());
NetAddr addr3(":8080");
println(addr3.to_string());
return 0;
}

59
third_party/libhv/unittest/hthread_test.cpp vendored Executable file
View File

@@ -0,0 +1,59 @@
#include "hthread.h"
#include "htime.h"
HTHREAD_ROUTINE(test_thread1) {
int cnt = 10;
while (cnt-- > 0) {
printf("tid=%ld time=%llums\n", hv_gettid(), gettimeofday_ms());
hv_msleep(100);
}
return 0;
}
class TestThread2 : public HThread {
protected:
virtual void run() {
int cnt = 10;
while (cnt-- > 0) {
printf("tid=%ld time=%llums\n", hv_gettid(), gettimeofday_ms());
hv_msleep(100);
}
}
};
class TestThread3 : public HThread {
protected:
virtual bool doPrepare() {
printf("doPrepare\n");
return true;
}
virtual void doTask() {
printf("tid=%ld time=%llums\n", hv_gettid(), gettimeofday_ms());
}
virtual bool doFinish() {
printf("doFinish\n");
return true;
}
};
int main() {
printf("c-style hthread_create\n");
hthread_t thread1 = hthread_create(test_thread1, NULL);
hthread_join(thread1);
printf("cpp-style override HThread::run\n");
TestThread2 thread2;
thread2.start();
thread2.stop();
printf("cpp-style override HThread::doTask\n");
TestThread3 thread3;
thread3.setSleepPolicy(HThread::SLEEP_UNTIL, 100);
thread3.start();
hv_sleep(1);
thread3.stop();
return 0;
}

23
third_party/libhv/unittest/hurl_test.cpp vendored Executable file
View File

@@ -0,0 +1,23 @@
#include <assert.h>
#include "hurl.h"
int main(int argc, char** argv) {
std::string strURL = "http://www.example.com/path?query#fragment";
HUrl url;
if (!url.parse(strURL)) {
printf("parse url %s error!\n", strURL.c_str());
return -1;
}
std::string dumpURL = url.dump();
printf("%s =>\n%s\n", strURL.c_str(), dumpURL.c_str());
assert(strURL == dumpURL);
const char* str = "中 文";
std::string escaped = HUrl::escape(str);
std::string unescaped = HUrl::unescape(escaped.c_str());
printf("%s => %s\n", str, escaped.c_str());
assert(str == unescaped);
return 0;
}

17
third_party/libhv/unittest/ifconfig_test.cpp vendored Executable file
View File

@@ -0,0 +1,17 @@
#include <stdio.h>
#include "ifconfig.h"
int main() {
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);
}
return 0;
}

44
third_party/libhv/unittest/listdir_test.cpp vendored Executable file
View File

@@ -0,0 +1,44 @@
#include <stdio.h>
#include "hdir.h"
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;
}

64
third_party/libhv/unittest/md5_test.c vendored Executable file
View File

@@ -0,0 +1,64 @@
/*
* @build: gcc -o bin/md5 unittest/md5_test.c util/md5.c -I. -Iutil
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "md5.h"
static void test() {
unsigned char ch = '1';
char md5[33] = {0};
hv_md5_hex(&ch, 1, md5, sizeof(md5));
assert(strcmp(md5, "c4ca4238a0b923820dcc509a6f75849b") == 0);
}
int main(int argc, char* argv[]) {
test();
if (argc < 2) {
printf("Usage: md5 file\n");
printf(" md5 -s string\n");
return -10;
}
char md5[33] = {0};
if (argc == 2) {
const char* filepath = argv[1];
FILE* fp = fopen(filepath, "rb");
if (fp == NULL) {
printf("Open file '%s' failed!\n", filepath);
return -20;
}
fseek(fp, 0, SEEK_END);
long filesize = ftell(fp);
// printf("filesize=%ld\n", filesize);
fseek(fp, 0, SEEK_SET);
unsigned char* filebuf = (unsigned char*)malloc(filesize);
size_t nread = fread(filebuf, 1, filesize, fp);
assert(nread == filesize);
hv_md5_hex(filebuf, filesize, md5, sizeof(md5));
free(filebuf);
fclose(fp);
}
else if (argc == 3) {
const char* flags = argv[1];
if (flags[0] == '-' && flags[1] == 's') {
hv_md5_hex((unsigned char*)argv[2], strlen(argv[2]), md5, sizeof(md5));
}
else {
printf("Unrecognized flags '%s'\n", flags);
return -40;
}
}
puts(md5);
return 0;
}

10
third_party/libhv/unittest/mkdir_test.c vendored Executable file
View File

@@ -0,0 +1,10 @@
#include "hbase.h"
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: mkdir_p dir\n");
return -1;
}
const char* dir = argv[1];
return hv_mkdir_p(dir);
}

34
third_party/libhv/unittest/nslookup_test.c vendored Executable file
View File

@@ -0,0 +1,34 @@
#include <stdio.h>
#include "hplatform.h" // inet_ntop
#include "dns.h" // nslookup
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: nslookup domain [nameserver]\n");
return -1;
}
const char* domain = argv[1];
const char* nameserver = "127.0.1.1";
#ifndef OS_LINUX
nameserver = "114.114.114.114";
// nameserver = "8.8.8.8";
#endif
if (argc > 2) {
nameserver = argv[2];
}
uint32_t addrs[16];
int naddr = nslookup(domain, addrs, 16, nameserver);
if (naddr < 0) {
return naddr;
}
char ip[16];
for (int i = 0; i < naddr; ++i) {
inet_ntop(AF_INET, (void*)&addrs[i], ip, 16);
printf("%s\n", ip);
}
return 0;
}

View File

@@ -0,0 +1,56 @@
#include <stdio.h>
#include <thread>
#include "hobjectpool.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
void msleep(unsigned int ms) {
#ifdef _WIN32
Sleep(ms);
#else
usleep(ms*1000);
#endif
}
class Task {
public:
Task() {printf("Task()\n");}
~Task() {printf("~Task()\n");}
void Do() {
printf("%p start do...\n", this);
msleep(4000);
printf("%p end do\n", this);
}
};
HObjectPool<Task> task_pool(1, 5);
void task_thread(int id) {
printf("thread %d run...\n", id);
HPoolObject<Task> pTask(task_pool);
if (pTask) {
pTask->Do();
}
else {
printf("No available task in pool\n");
}
printf("thread %d exit\n", id);
}
int main(int argc, char** argv) {
for (int i = 0; i < 10; ++i) {
new std::thread(task_thread, i);
}
msleep(5000);
for (int i = 10; i < 20; ++i) {
new std::thread(task_thread, i);
}
msleep(10000);
return 0;
}

16
third_party/libhv/unittest/ping_test.c vendored Executable file
View File

@@ -0,0 +1,16 @@
#include <stdio.h>
#include "icmp.h"
#include "hplatform.h"
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: ping host|ip\n");
return -10;
}
char* host = argv[1];
int ping_cnt = 4;
int ok_cnt = ping(host, ping_cnt);
printf("ping %d count, %d ok.\n", ping_cnt, ok_cnt);
return 0;
}

111
third_party/libhv/unittest/rbtree_test.c vendored Executable file
View File

@@ -0,0 +1,111 @@
#include <stdio.h>
#include <string.h>
#include "rbtree.h"
typedef int rbtree_key_type;
typedef int rbtree_val_type;
struct rbtree_entry {
struct rb_node rb_node;
rbtree_key_type key;
rbtree_val_type val;
};
int rbtree_insert(struct rb_root* root, struct rbtree_entry* entry) {
printf("insert %d\n", entry->key);
struct rb_node** n = &root->rb_node;
struct rb_node* parent = NULL;
struct rbtree_entry* e = NULL;
while (*n) {
parent = *n;
e = rb_entry(*n, struct rbtree_entry, rb_node);
if (entry->key < e->key) {
n = &(*n)->rb_left;
} else if (entry->key > e->key) {
n = &(*n)->rb_right;
} else {
return -1;
}
}
rb_link_node(&entry->rb_node, parent, n);
rb_insert_color(&entry->rb_node, root);
return 0;
}
int rbtree_remove(struct rb_root* root, struct rbtree_entry* entry) {
printf("remove %d\n", entry->key);
rb_erase(&entry->rb_node, root);
return 0;
}
struct rbtree_entry* rbtree_search(struct rb_root* root, const rbtree_key_type* key) {
struct rb_node* n = root->rb_node;
struct rbtree_entry* e = NULL;
while (n) {
e = rb_entry(n, struct rbtree_entry, rb_node);
if (*key < e->key) {
n = n->rb_left;
} else if (*key > e->key) {
n = n->rb_right;
} else {
return e;
}
}
return NULL;
}
void rbtree_entry_print(struct rbtree_entry* entry) {
if (entry == NULL) {
printf("null\n");
return;
}
printf("%d:%d\n", entry->key, entry->val);
}
int main() {
struct rb_root root = { NULL };
struct rbtree_entry* entry = NULL;
struct rbtree_entry entries[10];
for (int i = 0; i < 10; ++i) {
memset(&entries[i], 0, sizeof(struct rbtree_entry));
entries[i].key = i;
entries[i].val = i;
}
rbtree_insert(&root, &entries[1]);
rbtree_insert(&root, &entries[2]);
rbtree_insert(&root, &entries[3]);
rbtree_insert(&root, &entries[7]);
rbtree_insert(&root, &entries[8]);
rbtree_insert(&root, &entries[9]);
rbtree_insert(&root, &entries[4]);
rbtree_insert(&root, &entries[5]);
rbtree_insert(&root, &entries[6]);
rbtree_remove(&root, &entries[1]);
rbtree_remove(&root, &entries[9]);
rbtree_remove(&root, &entries[4]);
rbtree_remove(&root, &entries[6]);
int key = 5;
entry = rbtree_search(&root, &key);
rbtree_entry_print(entry);
key = 4;
entry = rbtree_search(&root, &key);
rbtree_entry_print(entry);
struct rb_node* node = NULL;
// while((node = rb_first(&root))) {
while((node = root.rb_node)) {
entry = rb_entry(node, struct rbtree_entry, rb_node);
rb_erase(node, &root);
rbtree_entry_print(entry);
memset(entry, 0, sizeof(struct rbtree_entry));
}
return 0;
}

10
third_party/libhv/unittest/rmdir_test.c vendored Executable file
View File

@@ -0,0 +1,10 @@
#include "hbase.h"
int main(int argc, char* argv[]) {
if (argc < 2) {
printf("Usage: rmdir_p dir\n");
return -1;
}
const char* dir = argv[1];
return hv_rmdir_p(dir);
}

24
third_party/libhv/unittest/sendmail_test.c vendored Executable file
View File

@@ -0,0 +1,24 @@
#include <stdio.h>
#include "smtp.h"
int main(int argc, char** argv) {
if (argc < 8) {
printf("Usage: sendmail smtp_server username password from to subject body\n");
return -10;
}
const char* smtp_server = argv[1];
const char* username = argv[2];
const char* password = argv[3];
mail_t mail;
mail.from = argv[4];
mail.to = argv[5];
mail.subject = argv[6];
mail.body = argv[7];
int status_code = sendmail(smtp_server, username, password, &mail);
printf("sendmail: %d %s\n", status_code, smtp_status_str((enum smtp_status)status_code));
return status_code == SMTP_STATUS_OK ? 0 : status_code;
}

64
third_party/libhv/unittest/sha1_test.c vendored Executable file
View File

@@ -0,0 +1,64 @@
/*
* @build: gcc -o bin/sha1 unittest/sha1_test.c util/sha1.c -I. -Iutil
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "sha1.h"
static void test() {
unsigned char ch = '1';
char sha1[41] = {0};
hv_sha1_hex(&ch, 1, sha1, sizeof(sha1));
assert(strcmp(sha1, "356a192b7913b04c54574d18c28d46e6395428ab") == 0);
}
int main(int argc, char* argv[]) {
test();
if (argc < 2) {
printf("Usage: sha1 file\n");
printf(" sha1 -s string\n");
return -10;
}
char sha1[41] = {0};
if (argc == 2) {
const char* filepath = argv[1];
FILE* fp = fopen(filepath, "rb");
if (fp == NULL) {
printf("Open file '%s' failed!\n", filepath);
return -20;
}
fseek(fp, 0, SEEK_END);
long filesize = ftell(fp);
// printf("filesize=%ld\n", filesize);
fseek(fp, 0, SEEK_SET);
unsigned char* filebuf = (unsigned char*)malloc(filesize);
size_t nread = fread(filebuf, 1, filesize, fp);
assert(nread == filesize);
hv_sha1_hex(filebuf, filesize, sha1, sizeof(sha1));
free(filebuf);
fclose(fp);
}
else if (argc == 3) {
const char* flags = argv[1];
if (flags[0] == '-' && flags[1] == 's') {
hv_sha1_hex((unsigned char*)argv[2], strlen(argv[2]), sha1, sizeof(sha1));
}
else {
printf("Unrecognized flags '%s'\n", flags);
return -40;
}
}
puts(sha1);
return 0;
}

62
third_party/libhv/unittest/sizeof_test.cpp vendored Executable file
View File

@@ -0,0 +1,62 @@
#include <stdio.h>
#include "hloop.h"
#include "hevent.h"
#include "EventLoop.h"
#include "EventLoopThread.h"
#include "EventLoopThreadPool.h"
#include "Channel.h"
#include "TcpClient.h"
#include "TcpServer.h"
#include "UdpClient.h"
#include "UdpServer.h"
#include "HttpMessage.h"
#include "Http1Parser.h"
#include "HttpContext.h"
#include "HttpServer.h"
#include "HttpHandler.h"
#include "HttpResponseWriter.h"
#include "WebSocketChannel.h"
#include "WebSocketParser.h"
#include "WebSocketServer.h"
#include "WebSocketClient.h"
using namespace hv;
int main() {
// event
printf("sizeof(struct hloop_s)=%lu\n", sizeof(struct hloop_s));
printf("sizeof(struct hevent_s)=%lu\n", sizeof(struct hevent_s));
printf("sizeof(struct hidle_s)=%lu\n", sizeof(struct hidle_s));
printf("sizeof(struct htimer_s)=%lu\n", sizeof(struct htimer_s));
printf("sizeof(struct htimeout_s)=%lu\n", sizeof(struct htimeout_s));
printf("sizeof(struct hperiod_s)=%lu\n", sizeof(struct hperiod_s));
printf("sizeof(struct hio_s)=%lu\n", sizeof(struct hio_s));
// evpp
printf("sizeof(class EventLoop)=%lu\n", sizeof(EventLoop));
printf("sizeof(class EventLoopThread)=%lu\n", sizeof(EventLoopThread));
printf("sizeof(class EventLoopThreadPool)=%lu\n", sizeof(EventLoopThreadPool));
printf("sizeof(class Channel)=%lu\n", sizeof(Channel));
printf("sizeof(class SocketChannel)=%lu\n", sizeof(SocketChannel));
printf("sizeof(class TcpClient)=%lu\n", sizeof(TcpClient));
printf("sizeof(class TcpServer)=%lu\n", sizeof(TcpServer));
printf("sizeof(class UdpClient)=%lu\n", sizeof(UdpClient));
printf("sizeof(class UdpServer)=%lu\n", sizeof(UdpServer));
// http
printf("sizeof(class HttpRequest)=%lu\n", sizeof(HttpRequest));
printf("sizeof(class HttpResponse)=%lu\n", sizeof(HttpResponse));
printf("sizeof(class Http1Parser)=%lu\n", sizeof(Http1Parser));
printf("sizeof(class HttpContext)=%lu\n", sizeof(HttpContext));
printf("sizeof(class HttpServer)=%lu\n", sizeof(HttpServer));
printf("sizeof(class HttpHandler)=%lu\n", sizeof(HttpHandler));
printf("sizeof(class HttpResponseWrite)=%lu\n", sizeof(HttpResponseWriter));
// websocket
printf("sizeof(class WebSocketChannel)=%lu\n", sizeof(WebSocketChannel));
printf("sizeof(class WebSocketParser)=%lu\n", sizeof(WebSocketParser));
printf("sizeof(class WebSocketClient)=%lu\n", sizeof(WebSocketClient));
printf("sizeof(class WebSocketServer)=%lu\n", sizeof(WebSocketServer));
return 0;
}

24
third_party/libhv/unittest/socketpair_test.c vendored Executable file
View File

@@ -0,0 +1,24 @@
#include <stdio.h>
#include "hsocket.h"
int main(int argc, char* argv[]) {
int sockfds[2];
if (Socketpair(AF_INET, SOCK_STREAM, 0, sockfds) != 0) {
printf("socketpair failed!\n");
return -1;
}
printf("Socketpair %d<=>%d\n", sockfds[0], sockfds[1]);
char sendbuf[] = "hello,world!";
char recvbuf[1460];
int nsend = send(sockfds[0], sendbuf, strlen(sendbuf), 0);
printf("sockfd:%d send %d bytes: %s\n", sockfds[0], nsend, sendbuf);
memset(recvbuf, 0, sizeof(recvbuf));
int nrecv = recv(sockfds[1], recvbuf, sizeof(recvbuf), 0);
printf("sockfd:%d recv %d bytes: %s\n", sockfds[1], nrecv, recvbuf);
closesocket(sockfds[0]);
closesocket(sockfds[1]);
return 0;
}

View File

@@ -0,0 +1,24 @@
#include "hthread.h"
#include "hmutex.h"
#define THREAD_NUM 10
std::mutex g_mutex;
HTHREAD_ROUTINE(test_synchronized) {
synchronized(g_mutex) {
hv_delay(1000);
printf("tid=%ld time=%llus\n", hv_gettid(), (unsigned long long)time(NULL));
}
return 0;
}
int main() {
hthread_t threads[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; ++i) {
threads[i] = hthread_create(test_synchronized, NULL);
}
for (int i = 0; i < THREAD_NUM; ++i) {
hthread_join(threads[i]);
}
return 0;
}

View File

@@ -0,0 +1,30 @@
#include <stdio.h>
#include "hthreadpool.h"
#include "hthread.h"
#include "htime.h"
void print_task(int i) {
printf("thread[%ld]: task[%d]\n", hv_gettid(), i);
hv_sleep(1);
}
int main(int argc, char** argv) {
HThreadPool tp(1, 4);
tp.start();
int i = 0;
for (; i < 10; ++i) {
tp.commit(print_task, i);
}
tp.wait();
for (; i < 20; ++i) {
tp.commit(print_task, i);
}
tp.wait();
return 0;
}

373
third_party/libhv/unittest/webbench.c vendored Executable file
View File

@@ -0,0 +1,373 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> // for gethostbyname
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
int Connect(const char* host, int port) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
in_addr_t inaddr = inet_addr(host);
if (inaddr != INADDR_NONE) {
addr.sin_addr.s_addr = inaddr;
}
else {
struct hostent* phe = gethostbyname(host);
if (phe == NULL) {
return -1;
}
memcpy(&addr.sin_addr, phe->h_addr_list[0], phe->h_length);
}
addr.sin_port = htons(port);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
return -2;
}
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("connect");
return -3;
}
return sock;
}
#define METHOD_GET 0
#define METHOD_HEAD 1
#define METHOD_OPTIONS 2
#define METHOD_TRACE 3
#define VERSION "webbench/1.19.3.15"
int verbose = 0;
int quiet = 0;
volatile int timerexpired = 0; // for timer
int time = 30;
int clients = 1;
char host[64] = {0};
int port = 80;
char* proxy_host = NULL;
int proxy_port = 80;
int method = METHOD_GET;
int http = 1; // 1=HTTP/1.1 0=HTTP/1.0
int keepalive = 0;
const char* url = NULL;
#define REQUEST_SIZE 2048
char request[REQUEST_SIZE] = {0};
char buf[1460] = {0};
int mypipe[2]; // IPC
static const char options[] = "?hVvq01kt:p:c:";
static const struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'V'},
{"verbose", no_argument, NULL, 'v'},
{"quiet", no_argument, NULL, 'q'},
{"time", required_argument, NULL, 't'},
{"proxy", required_argument, NULL, 'p'},
{"clients", required_argument, NULL, 'c'},
{"http10", no_argument, NULL, '0'},
{"http11", no_argument, NULL, '1'},
{"keepalive", no_argument, NULL, 'k'},
{"get", no_argument, &method, METHOD_GET},
{"head", no_argument, &method, METHOD_HEAD},
{"options", no_argument, &method, METHOD_OPTIONS},
{"trace", no_argument, &method, METHOD_TRACE},
{NULL, 0, NULL, 0}
};
void print_usage() {
printf("Usage: webbench [%s] URL\n", options);
puts("\n\
Options:\n\
-?|-h|--help Print this information.\n\
-V|--version Print version.\n\
-v|--verbose Print verbose.\n\
-q|--quiet Print quiet.\n\
-0|--http10 Use HTTP/1.0 protocol.\n\
-1|--http11 Use HTTP/1.1 protocol.\n\
-k|--keepalive Connection: keep-alive.\n\
-t|--time <sec> Run benchmark for <sec> seconds. Default 30.\n\
-p|--proxy <server:port> Use proxy server for request.\n\
-c|--clients <n> Run <n> HTTP clients. Default one.\n\
--get Use GET request method.\n\
--head Use HEAD request method.\n\
--options Use OPTIONS request method.\n\
--trace Use TRACE request method.\n\
");
}
int parse_cmdline(int argc, char** argv) {
int opt = 0;
int opt_idx = 0;
while ((opt=getopt_long(argc, argv, options, long_options, &opt_idx)) != EOF) {
switch (opt) {
case '?':
case 'h': print_usage(); exit(1);
case 'V': puts(VERSION); exit(1);
case 'v': verbose = 1; break;
case 'q': quiet = 1; break;
case '0': http = 0; break;
case '1': http = 1; break;
case 'k': keepalive = 1; break;
case 't': time = atoi(optarg); break;
case 'c': clients = atoi(optarg); break;
case 'p':
{
// host:port
char* pos = strrchr(optarg, ':');
proxy_host = optarg;
if (pos == NULL) break;
if (pos == optarg ||
pos == optarg + strlen(optarg) - 1) {
printf("Error option --proxy\n");
return -2;
}
*pos = '\0';
proxy_port = atoi(pos+1);
}
break;
}
}
if (optind == argc) {
printf("Missing URL\n");
return -2;
}
url = argv[optind];
return 0;
}
static void alarm_handler(int singal) {
timerexpired = 1;
}
int main(int argc, char** argv) {
if (argc == 1) {
print_usage();
return 2;
}
int ret = parse_cmdline(argc, argv);
if (ret != 0) {
return ret;
}
printf("%d clients, running %d sec\n", clients, time);
// domain port url
const char* req_url = "/";
if (proxy_host) {
strncpy(host, proxy_host, sizeof(host));
port = proxy_port;
} else {
// http://host:port/path
const char* pos1 = strstr(url, "http://");
if (pos1 == NULL) {
pos1 = url;
} else {
pos1 += strlen("http://");
}
const char* pos2 = strchr(pos1, '/');
if (pos2 == NULL) {
pos2 = url + strlen(url);
} else {
req_url = pos2;
}
int len = pos2 - pos1;
char* server = (char*)malloc(len+1);
memcpy(server, pos1, len);
server[len] = '\0';
char* pos3 = strrchr(server, ':');
if (pos3 == NULL) {
port = 80;
} else {
*pos3 = '\0';
port = atoi(pos3+1);
}
strncpy(host, server, sizeof(host));
free(server);
}
char Host[256];
snprintf(Host, sizeof(Host), "Host: %s:%d\r\n", host, port);
printf("%s", Host);
// test connect
int sock = Connect(host, port);
if (sock < 0) {
printf("Connect failed!\n");
return -20;
} else {
printf("Connect test OK!\n");
close(sock);
}
// build request
switch (method) {
case METHOD_GET:
default:
strcpy(request, "GET");
break;
case METHOD_HEAD:
strcpy(request, "HEAD");
break;
case METHOD_OPTIONS:
strcpy(request, "OPTIONS");
break;
case METHOD_TRACE:
strcpy(request, "TRACE");
break;
}
strcat(request, " ");
strcat(request, req_url);
strcat(request, " ");
if (http == 0) {
strcat(request, "HTTP/1.0");
} else if (http == 1) {
strcat(request, "HTTP/1.1");
}
strcat(request, "\r\n");
strcat(request, "User-Agent: webbench/1.18.3.15\r\n");
strcat(request, Host);
strcat(request, "Cache-Control: no-cache\r\n");
if (keepalive) {
strcat(request, "Connection: keep-alive\r\n");
}
else {
strcat(request, "Connection: close\r\n");
}
strcat(request, "\r\n");
if (!quiet) {
printf("%s", request);
}
// IPC
if (pipe(mypipe) < 0) {
perror("pipe");
exit(20);
}
// fork childs
pid_t pid = 0;
FILE* fp = NULL;
long long succeed = 0, failed = 0, bytes = 0;
int childs = clients;
int i;
for (i = 0; i < childs; ++i) {
pid = fork();
if (pid < 0) {
perror("fork");
exit(-10);
}
if (pid == 0) {
// child
//printf("child[%d] start\n", getpid());
signal(SIGALRM, alarm_handler);
alarm(time);
int sock = -1;
int len = strlen(request);
int wrbytes, rdbytes;
while (1) {
connect:
if (timerexpired) break;
if (sock == -1) {
sock = Connect(host, port);
}
if (sock < 0) {
++failed;
continue;
}
int total_rdbytes = 0;
write:
if (timerexpired) break;
wrbytes = write(sock, request, len);
if (verbose) {
printf("write %d bytes\n", wrbytes);
}
if (wrbytes != len) {
++failed;
goto close;
}
if (verbose) {
printf("%s\n", request);
}
read:
if (timerexpired) break;
rdbytes = read(sock, buf, sizeof(buf));
if (verbose) {
printf("read %d bytes\n", rdbytes);
}
if (rdbytes <= 0) {
++failed;
goto close;
}
if (verbose) {
printf("%.*s\n", rdbytes, buf);
}
static int s_rdbytes = 0;
if (s_rdbytes == 0) {
s_rdbytes = rdbytes;
}
bytes += rdbytes;
total_rdbytes += rdbytes;
if (total_rdbytes < s_rdbytes) {
// NOTE: some http server head and body send not one packet.
goto read;
}
++succeed;
close:
if (!keepalive) {
close(sock);
sock = -1;
}
}
fp = fdopen(mypipe[1], "w");
if (fp == NULL) {
perror("fdopen");
return 30;
}
fprintf(fp, "%lld %lld %lld\n", succeed, failed, bytes);
fclose(fp);
//printf("child[%d] end\n", getpid());
return 0;
}
}
fp = fdopen(mypipe[0], "r");
if (fp == NULL) {
perror("fdopen");
return 30;
}
while (1) {
long long i,j,k;
fscanf(fp, "%lld %lld %lld", &i, &j, &k);
succeed += i;
failed += j;
bytes += k;
if (--childs==0) break;
}
fclose(fp);
printf("recv %lld bytes/sec, %lld succeed, %lld failed\n",
bytes/time,
succeed,
failed);
return 0;
}