diff --git a/CMakeLists.txt b/CMakeLists.txt index e429dfa..5ffb35d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,29 +1,30 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.10 FATAL_ERROR) - INCLUDE(CMakeDependentOption) +OPTION(VCPE_AGENT "Enable vCPE agent test application" OFF) +OPTION(VCPE_PPPOE "Enable vCPE work befof PPPoE mode" OFF) +OPTION(USED_OPENDHCPD "DHCP server for vCPE" OFF) +OPTION(USED_OPENDHCPDDNS "DHCP And DNS server for vCPE" OFF) +OPTION(USED_USER_VNI "Support pass user vni id from console command line" OFF) +OPTION(USED_JSON_VALIDATE "Support json protocol field validate" OFF) +OPTION(BUILD_TESTING "Enable tests" OFF) +# 数据库开关 +OPTION(USED_REDIS "Add redis database support for vCPE" OFF) +OPTION(USED_MYSQL "Add mysql database support for vCPE" OFF) +OPTION(USED_SQLITE "Add sqlite3 database support for vCPE" OFF) +CMAKE_DEPENDENT_OPTION(USED_HTTP_SVR "Build-in http(s) server support" ON "USED_OPENDHCPD OR USED_OPENDHCPDDNS" OFF) +CMAKE_DEPENDENT_OPTION(USED_LWIP "PPPoE of LWIP support for vCPE" ON "VCPE_PPPOE" OFF) +CMAKE_DEPENDENT_OPTION(USED_ZMQ "ZeroMQ support for vCPE" ON "VCPE_PPPOE" OFF) + LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/depend) IF (BUILD_TESTING) INCLUDE(doctest_framework) ENDIF () INCLUDE(system_libs) -SET(VCPE_VERSION "1.0.1") +SET(VCPE_VERSION "1.2.0") PROJECT(vCPE VERSION "${VCPE_VERSION}") -OPTION(VCPE_AGENT "Enable vCPE agent test application" OFF) -OPTION(USED_LWIP "PPPoE of LWIP support for vCPE" OFF) -OPTION(USED_OPENDHCPD "DHCP server for vCPE" OFF) -OPTION(USED_OPENDHCPDDNS "DHCP And DNS server for vCPE" OFF) -OPTION(USED_USER_VNI "Support pass user vni id from console command line" OFF) -OPTION(BUILD_TESTING "Enable tests" OFF) -CMAKE_DEPENDENT_OPTION(USED_HTTP_SVR "Build-in http(s) server support" ON "USED_OPENDHCPD OR USED_OPENDHCPDDNS" OFF) - -# 数据库开关 -OPTION(USED_REDIS "Add redis database support for vCPE" OFF) -OPTION(USED_MYSQL "Add mysql database support for vCPE" OFF) -OPTION(USED_SQLITE "Add sqlite3 database support for vCPE" OFF) - SET(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig") SET(URI_HOME "${CMAKE_SOURCE_DIR}/libs") @@ -82,6 +83,10 @@ SET(COMMON_LIBS "") INCLUDE(./depend/third_libs.cmake) +IF (USED_JSON_VALIDATE) + LIST(APPEND COMMON_DEFINE "-DJSON_SCHEMA_ON") +ENDIF () + IF (USED_USER_VNI) LIST(APPEND COMMON_DEFINE "-DUSERVNI_ON") MESSAGE("Select Option USED_USER_VNI") @@ -92,6 +97,16 @@ IF (USED_HTTP_SVR) MESSAGE("Select Option USED_HTTP_SVR") ENDIF () +IF (USED_ZMQ) + LIST(APPEND COMMON_DEFINE "-DZEROMQ_ON") + MESSAGE("Select Option USED_ZMQ") +ENDIF () + +IF (VCPE_PPPOE) + LIST(APPEND COMMON_DEFINE "-DPPPOE_ON") + MESSAGE("Select Option VCPE_PPPOE") +ENDIF () + IF (USED_LWIP) LIST(APPEND COMMON_DEFINE "-DLWIP_ON") MESSAGE("Select Option USED_LWIP") diff --git a/config/vcpe.cfg b/config/vcpe.cfg index 319ff48..7292984 100644 --- a/config/vcpe.cfg +++ b/config/vcpe.cfg @@ -14,7 +14,7 @@ application: agent: { iptv_report_url = "http://10.0.0.1:50012/vcpe/dhcp/info"; # IPTV 设备上报接口 - moniter_rep_url = "http://10.0.0.1:50012/vcpe/dhcp/restart"; # vCPE设备上下线接口 + moniter_rep_url = ""; # vCPE设备上下线接口 }; # 硬件监控相关配置内容 @@ -24,11 +24,6 @@ application: memory = true; # 是否开启内存监控 disk = true; # 是否开启磁盘空间占用监控 sensor = true; # 是否开启传感器状态监控 - - cpu_refresh = 1; # CPU 状态刷新频率(秒) - mem_refresh = 10; # 内存状态刷新频率(秒) - disk_refresh = 10; # 磁盘状态刷新频率(秒) - sensor_refresh = 10; # 传感器状态刷新频率(秒) }; # 数据库相关配置 diff --git a/config/zlog.conf b/config/zlog.conf index 6376df4..842435a 100644 --- a/config/zlog.conf +++ b/config/zlog.conf @@ -9,7 +9,7 @@ buffer max = 2MB rotate lock file = self default format = "%d(%F %T.%l) %-6V (%c:%f:%L) %m%n" -file perms = 600 +file perms = 644 fsync period = 1K [levels] @@ -22,8 +22,8 @@ normal = "[%d(%F %T).%ms][%-6V][%c][%f:%L] %m" [rules] *.* >stdout; normal -*.INFO "./log/%c.log", \ - 1MB * 12 ~ "%E(HOME)/log/%c.%D(%F) #2r #3s.log"; \ +*.INFO "/var/log/vcpe/%M(vni)_vcpe.log", \ + 1MB * 12 ~ "/var/log/vcpe/%M(vni)_vcpe_.%D(%F) #2r #3s.log"; \ normal diff --git a/depend/json-c-0.16.tar.gz b/depend/json-c-0.16.tar.gz new file mode 100644 index 0000000..53ee6be Binary files /dev/null and b/depend/json-c-0.16.tar.gz differ diff --git a/depend/third_libs.cmake b/depend/third_libs.cmake index 43f01ab..7dd46b0 100644 --- a/depend/third_libs.cmake +++ b/depend/third_libs.cmake @@ -1,10 +1,36 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.14 FATAL_ERROR) INCLUDE(FetchContent) +PKG_SEARCH_MODULE(LIBCURL QUIET libcurl) +PKG_SEARCH_MODULE(LIBSSL QUIET libssl) +PKG_SEARCH_MODULE(LIBCRYPTO QUIET libcrypto) +IF (USED_ZMQ) + PKG_SEARCH_MODULE(LIBZMQ QUIET libzmq) + IF (NOT LIBZMQ_FOUND) + LINUX_INSTALL_SYSTEM_PACKAGE() + ENDIF () +ENDIF () +IF ((NOT LIBCRYPTO_FOUND) OR (NOT LIBSSL_FOUND) OR (NOT LIBCURL_FOUND)) + LINUX_INSTALL_SYSTEM_PACKAGE() +ENDIF () + +LIST(APPEND COMMON_LIBS "${LIBCURL_LDFLAGS} ${LIBSSL_LDFLAGS} ${LIBCRYPTO_LDFLAGS}") +LIST(APPEND COMMON_LIBS "${LIBZMQ_LDFLAGS}") +LIST(APPEND COMMON_LIBS "-lm -lpthread") + PKG_SEARCH_MODULE(LIBUV QUIET libuv) PKG_SEARCH_MODULE(LIBCONFIG QUIET libconfig) FIND_LIBRARY(LIBZLOG zlog PATHS "/usr/local/lib") +IF (USED_JSON_VALIDATE) + PKG_CHECK_MODULES(LIBJSON-C QUIET json-c>=0.13) + IF (NOT LIBJSON-C_FOUND) + FETCHCONTENT_DECLARE(libjson-c + URL file://${CMAKE_SOURCE_DIR}/depend/json-c-0.16.tar.gz + URL_MD5 a549a833f886d427148fb5710c3e613e + ) + ENDIF () +ENDIF () IF (NOT LIBUV_FOUND) FETCHCONTENT_DECLARE(libuv URL file://${CMAKE_SOURCE_DIR}/depend/libuv-v1.44.2.tar.gz @@ -35,6 +61,11 @@ IF (LIBZLOG STREQUAL "LIBZLOG-NOTFOUND") FETCHCONTENT_MAKEAVAILABLE(zlog) ENDIF () +IF (USED_JSON_VALIDATE) + IF (NOT LIBJSON-C_FOUND) + FETCHCONTENT_MAKEAVAILABLE(libjson-c) + ENDIF () +ENDIF () IF (NOT LIBUV_FOUND) MESSAGE(STATUS "libuv not found, will be used source code to build it ...") FETCHCONTENT_GETPROPERTIES(libuv) @@ -75,4 +106,24 @@ IF (LIBZLOG STREQUAL "LIBZLOG-NOTFOUND") ELSE () MESSAGE(STATUS "zlog found of ${LIBZLOG}") LIST(APPEND COMMON_LIBS "${LIBZLOG}") +ENDIF () + +IF (USED_JSON_VALIDATE) + IF (NOT LIBJSON-C_FOUND) + MESSAGE(STATUS "json-c not found, will be used source code to build it ...") + FETCHCONTENT_GETPROPERTIES(libjson-c) + IF (NOT libjson-c_POPULATED) + FETCHCONTENT_POPULATE(libjson-c) + ADD_SUBDIRECTORY(${libjson-c_SOURCE_DIR} ${libjson-c_BINARY_DIR}) + ENDIF () + EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E make_directory "json-c" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${libjson-c_BINARY_DIR}/json.h" "./json-c/" + COMMAND ${CMAKE_COMMAND} -E copy_if_different "${libjson-c_BINARY_DIR}/json_config.h" "." + WORKING_DIRECTORY ${libjson-c_SOURCE_DIR}) + INCLUDE_DIRECTORIES(${libjson-c_SOURCE_DIR}) + LIST(APPEND COMMON_LIBS "json-c") + ELSE () + MESSAGE(STATUS "json-c found ${LIBJSON-C_VERSION} at ${LIBJSON-C_LIBRARY_DIRS}") + LIST(APPEND COMMON_LIBS "${LIBJSON-C_LDFLAGS}") + ENDIF () ENDIF () \ No newline at end of file diff --git a/srcs/CMakeLists.txt b/srcs/CMakeLists.txt index e718093..f26eeef 100644 --- a/srcs/CMakeLists.txt +++ b/srcs/CMakeLists.txt @@ -6,19 +6,6 @@ ENDIF () PROJECT(${PROJECT_TARGET}) -PKG_SEARCH_MODULE(LIBCURL QUIET libcurl) -PKG_SEARCH_MODULE(LIBSSL QUIET libssl) -PKG_SEARCH_MODULE(LIBCRYPTO QUIET libcrypto) -PKG_SEARCH_MODULE(LIBZMQ QUIET libzmq) - -IF ((NOT LIBZMQ_FOUND) OR (NOT LIBCRYPTO_FOUND) OR (NOT LIBSSL_FOUND) OR (NOT LIBCURL_FOUND)) - LINUX_INSTALL_SYSTEM_PACKAGE() -ENDIF () - -LIST(APPEND COMMON_LIBS "${LIBCURL_LDFLAGS} ${LIBSSL_LDFLAGS} ${LIBCRYPTO_LDFLAGS}") -LIST(APPEND COMMON_LIBS "${LIBZMQ_LDFLAGS}") -LIST(APPEND COMMON_LIBS "-lm -lpthread") - ADD_DEFINITIONS(${COMMON_DEFINE}) INCLUDE_DIRECTORIES(include ./ ./include ./libs/include ./lwip/src/include ./lwip/src/arch_linux/include @@ -29,7 +16,7 @@ SET(CMAKE_C_STANDARD 99) FILE(GLOB VCPE_HEADS include/*.h include/uthash/*.h include/s2j/*.h ./httpserver/include/*.h ./httpserver/src/haywire/*.h ./httpserver/src/haywire/configuration/*.h) -IF (USED_LWIP) +IF (VCPE_PPPOE) AUX_SOURCE_DIRECTORY(pppoe VCPE_SRC) AUX_SOURCE_DIRECTORY(user VCPE_SRC) ENDIF () diff --git a/srcs/libs/CMakeLists.txt b/srcs/libs/CMakeLists.txt index b9924bf..4ca2b34 100644 --- a/srcs/libs/CMakeLists.txt +++ b/srcs/libs/CMakeLists.txt @@ -17,13 +17,20 @@ AUX_SOURCE_DIRECTORY(banner C_SRC) AUX_SOURCE_DIRECTORY(configure C_SRC) AUX_SOURCE_DIRECTORY(network C_SRC) AUX_SOURCE_DIRECTORY(task C_SRC) -AUX_SOURCE_DIRECTORY(mq C_SRC) +IF (USED_ZMQ) + AUX_SOURCE_DIRECTORY(mq C_SRC) +ENDIF () AUX_SOURCE_DIRECTORY(cmdline C_SRC) AUX_SOURCE_DIRECTORY(crypto C_SRC) AUX_SOURCE_DIRECTORY(hardware C_SRC) AUX_SOURCE_DIRECTORY(protocol C_SRC) AUX_SOURCE_DIRECTORY(fs_watch C_SRC) AUX_SOURCE_DIRECTORY(zlog_module C_SRC) + +IF (USED_JSON_VALIDATE) + ADD_SUBDIRECTORY(./json/json_schema) +ENDIF () + IF (USED_HTTP_SVR) AUX_SOURCE_DIRECTORY(mongoose C_SRC) ENDIF () @@ -62,6 +69,10 @@ ADD_LIBRARY(${LIB_PROJECT_TARGET} ${C_SRC} ${C_HEADS}) TARGET_LINK_LIBRARIES(${LIB_PROJECT_TARGET} ${COMMON_LIBS}) +IF (USED_JSON_VALIDATE) + TARGET_LINK_LIBRARIES(${LIB_PROJECT_TARGET} jsoncdac) +ENDIF () + IF (USED_OPENDHCPD) TARGET_LINK_LIBRARIES(${LIB_PROJECT_TARGET} opendhcpd) ENDIF () diff --git a/srcs/libs/cmdline/cmd_menu.c b/srcs/libs/cmdline/cmd_menu.c index 2984ebe..f57c451 100644 --- a/srcs/libs/cmdline/cmd_menu.c +++ b/srcs/libs/cmdline/cmd_menu.c @@ -186,8 +186,11 @@ static int on_cmd2(void *pTbl[], const char *pName, void *pInfo) { } pJsonStr = cJSON_PrintUnformatted(pJsonObj); - ret = mq_cmd_run(pSvr, pJsonStr); - +#ifdef ZEROMQ_ON + ret = mq_cmd_run(pSvr, pJsonStr); +#else + ret = ERR_SUCCESS; +#endif cJSON_Delete(pJsonObj); free((void *)pJsonStr); diff --git a/srcs/libs/configure/config.c b/srcs/libs/configure/config.c index 2500260..abe896a 100644 --- a/srcs/libs/configure/config.c +++ b/srcs/libs/configure/config.c @@ -73,11 +73,6 @@ static CFG_ITEM g_cfgItem[] = { DEF_CFG_ITEM(CFG_WATCH_MEMORY, "watch_params.memory", VAL_BOOL, "1", "Monitor memory information"), DEF_CFG_ITEM(CFG_WATCH_DISK, "watch_params.disk", VAL_BOOL, "1", "Monitor disk partition information"), DEF_CFG_ITEM(CFG_WATCH_SENSOR, "watch_params.sensor", VAL_BOOL, "1", "Sensor information refresh frequency"), - /* 系统监控设备刷频率 */ - DEF_CFG_ITEM(CFG_CPU_REFRESH, "watch_params.cpu_refresh", VAL_INT, "10", "CPU information refresh frequency"), - DEF_CFG_ITEM(CFG_MEM_REFRESH, "watch_params.mem_refresh", VAL_INT, "10", "Memory information refresh frequency"), - DEF_CFG_ITEM(CFG_DISK_REFRESH, "watch_params.disk_refresh", VAL_INT, "10", "Disk information refresh frequency"), - DEF_CFG_ITEM(CFG_SENSOR_REFRESH, "watch_params.sensor_refresh", VAL_INT, "10", "Sensor information refresh frequency"), /* 数据库相配置 */ /* Redis配置 */ #ifdef USED_REDIS @@ -98,10 +93,12 @@ static CFG_ITEM g_cfgItem[] = { DEF_CFG_ITEM(CFG_DB_SQLITE_DB_NAME, "database.sqlite_dbname", VAL_STR, "", "SQLite3 database file name"), DEF_CFG_ITEM(CFG_DB_SQLITE_PASSWD, "database.sqlite_passwd", VAL_STR, ".main", "SQLite3 database password"), #endif +#ifdef ZEROMQ_ON /* 消息队列相配置 */ /* ZeroMq配置 */ DEF_CFG_ITEM(CFG_MQ_SVR_PORT, "zero_mq.svr_port", VAL_INT, "6278", "ZeroMQ server port"), DEF_CFG_ITEM(CFG_MQ_DATA_PATH, "zero_mq.agent_addr", VAL_STR, "ipc:///tmp/msg_fifo0", "ZeroMQ Agent data path"), +#endif /* vxLan 隧道配置 */ DEF_CFG_ITEM(CFG_VXLAN_NIC_NAME, "vxlan_wan.nic", VAL_STR, "", "Network card name to send data"), DEF_CFG_ITEM(CFG_VXLAN_SUPPORT, "vxlan_wan.enable", VAL_BOOL, "1", "Is support vxLan tune"), diff --git a/srcs/libs/configure/config_help.c b/srcs/libs/configure/config_help.c index 218229c..1f7c22a 100644 --- a/srcs/libs/configure/config_help.c +++ b/srcs/libs/configure/config_help.c @@ -121,22 +121,6 @@ int cfg_get_watch_sensor() { return cfg_get_bool_value(CFG_WATCH_SENSOR); } -unsigned int cfg_get_cpu_refresh_period() { - return cfg_get_integral_value(CFG_CPU_REFRESH); -} - -unsigned int cfg_get_mem_refresh_period() { - return cfg_get_integral_value(CFG_MEM_REFRESH); -} - -unsigned int cfg_get_disk_refresh_period() { - return cfg_get_integral_value(CFG_DISK_REFRESH); -} - -unsigned int cfg_get_sensor_refresh_period() { - return cfg_get_integral_value(CFG_SENSOR_REFRESH); -} - #ifdef USED_SQLITE const char *cfg_get_sqlite_db_name() { return cfg_get_string_value(CFG_DB_SQLITE_DB_NAME); @@ -183,10 +167,12 @@ const char *cfg_get_mysql_database() { } #endif +#ifdef ZEROMQ_ON int cfg_get_zero_mq_port() { return (unsigned short)cfg_get_integral_value(CFG_MQ_SVR_PORT); } const char *cfg_get_zero_mq_data_path() { return cfg_get_string_value(CFG_MQ_DATA_PATH); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/srcs/libs/crypto/symmetric.c b/srcs/libs/crypto/symmetric.c index d18fb62..5d713ae 100644 --- a/srcs/libs/crypto/symmetric.c +++ b/srcs/libs/crypto/symmetric.c @@ -68,7 +68,7 @@ static int sha1prng_for_aes_key(const char *pKey, unsigned char *pShaPrng16) { case AES128_ECB_PKCS7PADDING_SHA1PRNG: \ if (sha1prng_for_aes_key(pKey, keyBuf) != ERR_SUCCESS) { \ EVP_CIPHER_CTX_cleanup(pCtx); \ - return -ERR_AES128_KEYGEN; \ + return -ERR_AES_KEYGEN; \ } \ pCipher = EVP_aes_128_ecb(); \ break; \ @@ -165,8 +165,8 @@ int symmetric_decrypto(AES_TYPE algorithmType, return -ERR_EVP_UPDATE; } - *pOutBuf = pAesBuf; - pAesBuf += enBytes; + *pOutBuf = pAesBuf; + pAesBuf += enBytes; *pOutSize += enBytes; if (EVP_DecryptFinal_ex(pCtx, pAesBuf, &enBytes) == 0) { @@ -239,8 +239,8 @@ int symmetric_encrypto(AES_TYPE algorithmType, return -ERR_EVP_UPDATE; } - *pOutBuf = pAesBuf; - pAesBuf += enBytes; + *pOutBuf = pAesBuf; + pAesBuf += enBytes; *pOutSize += enBytes; if (EVP_EncryptFinal_ex(pCtx, pAesBuf, &enBytes) == 0) { diff --git a/srcs/libs/docs/json_schema/README.md b/srcs/libs/docs/json_schema/README.md new file mode 100644 index 0000000..9ac96c3 --- /dev/null +++ b/srcs/libs/docs/json_schema/README.md @@ -0,0 +1,130 @@ +# json-c d'accord library (libjsoncdac) + +jsonc-daccord is a lightweight JSON Schema validation library written in C, and is taking advantage of the libjson-c library. + +## Design Goals + +The goal is to have a lightweight JSON Schema validation implementation in C using json-c. json-c is popular in OpenWRT communities. Initially I just wanted it to support a small subset of JSON Schema to suit a need to validate simple json files. See the minimum build supports below. However to suit a broader audience, supporting more JSON Schema is important. + +Currently the footprint of libjsoncdac.so is 8KB. The keep the footprint from bloating out, new features should be selectable using CMake options. + +Minimal build supports: +- all: type, enum, required, properties, const. +- objects: +- strings: minLength, maxLength. +- integers and doubles: minimum, maximum. +- arrays: minItems, maxItems, uniqeItems, items. + +## Example Use + +Public headers: + +See [jsoncdaccord.h](include/jsoncdaccord.h) + +```C + int jdac_validate_file(const char *jsonfile, const char *jsonschemafile); + int jdac_validate(json_object *jobj, json_object *jschema); + int jdac_ref_set_localpath(const char *_localpath); + + const char* jdac_errorstr(unsigned int jdac_errors); +``` + +Link your binary to: `-ljsoncdac -ljson-c` + +Use the #include header: `#include ` + +Example C code: + +```C +#include +#include +#include + +int main(int argc, char *argv[]) +{ + char *json_file = "test.json"; + char *schema_file = "schema.json"; + + // optional: load referenced schema files from filesystem + char *localpath = "/my/path/to_json_files/"; + jdac_ref_set_localpath(localpath); + + printf("validating %s with %s\n", json_file, schema_file); + int err = jdac_validate_file(json_file, schema_file); + if (err==JDAC_ERR_VALID) { + printf("validation ok\n"); + } else { + printf("validate failed %d: %s\n", err, jdac_errorstr(err)); + } + return err; +} +``` + +See [jdac-cli.c](libjsoncdac/jdac-cli.c) as well. + +## Install + +Building from source: + +Install json-c and libcmocka-dev (used in the debug builds). + +- Release version: + +``` +git clone --branch libjsoncdac-0.2 https://github.com/domoslabs/jsonc-daccord &&\ +cd jsonc-daccord && mkdir build && cd build &&\ +cmake .. -DCMAKE_BUILD_TYPE=Release && make && sudo make install +``` + +- Debug version: +``` +git clone --branch libjsoncdac-0.2 https://github.com/domoslabs/jsonc-daccord &&\ +cd jsonc-daccord && mkdir build && cd build &&\ +cmake .. -DCMAKE_BUILD_TYPE=Debug && make && sudo make install +``` + +Note: After install you might need to run `sudo ldconfig`. + +## CMake Options + +build options: + +| option | description | +| :------------------------- | :------------------------------------------------------- | +| CMAKE_BUILD_TYPE | Build as Release or Debug. Default: Release. | +| RUN_TEST_SUITE | Run JSON Schema test suite (CMAKE_BUILD_TYPE=Debug Only) | +| BUILD_PATTERN | Support *pattern*. | +| BUILD_PATTERNPROPERTIES | Support *patternProperties* | +| BUILD_ADDITIONALPROPERTIES | Support *additionalProperties* | +| BUILD_PROPERTYNAMES | Support *propertyNames* | +| BUILD_SUBSCHEMALOGIC | Support *allOf*, *anyOf*, *oneOf*, *not*, *if-then-else* | +| BUILD_CONTAINS | Support *contains*, *minContains*, and *maxContains* | +| BUILD_DOWNLOAD | Support downloading referenced schema files | +| BUILD_STORE | Support build a list of schema uri, id, and anchors | +| BUILD_REF | Support *$ref* keyword. load schemas by file. | + + Note: All BUILD_* options are selected by default + +## Run tests +For debug builds: +``` +ctest +ctest -V # to see output of tests +``` + +Running test suites are currently optional, and are select with `RUN_TEST_SUITE=ON` in the cmake options. + +## Command Line Interface +You can try the library with the jdac-cli command. + +```/tmp/domos/domosqos-sta_statistics_json +jdac-cli -h +``` +## To do +- prevent infinite recursion + +## Related links + +- https://json-schema.org/specification.html +- https://github.com/json-schema-org/JSON-Schema-Test-Suite +- https://github.com/json-c/json-c diff --git a/srcs/libs/docs/json_schema/json/flows.json b/srcs/libs/docs/json_schema/json/flows.json new file mode 100644 index 0000000..43d7ca9 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/flows.json @@ -0,0 +1,1132 @@ +{ + "flows": [ + { + "flow_id": "91", + "service_name": "Cloudflare", + "master_protocol": "HTTP", + "sport": 58692, + "dport": 80, + "src": "192.168.1.190", + "dst": "104.20.145.10", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "120", + "service_name": "Cloudflare", + "master_protocol": "HTTP", + "sport": 58694, + "dport": 80, + "src": "192.168.1.190", + "dst": "104.20.144.10", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "93", + "service_name": "SkypeCall", + "master_protocol": "STUN", + "sport": 13389, + "dport": 1434, + "src": "192.168.1.223", + "dst": "10.20.32.177", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "59", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 80, + "dport": 60029, + "src": "104.199.241.133", + "dst": "192.168.1.223", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "36", + "service_name": "Dropbox", + "master_protocol": "Unknown", + "sport": 17500, + "dport": 17500, + "src": "192.168.1.190", + "dst": "192.168.1.255", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "119", + "service_name": "DNS", + "master_protocol": "Unknown", + "sport": 58707, + "dport": 53, + "src": "35.97.167.44", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "137", + "service_name": "Slack", + "master_protocol": "DNS", + "sport": 61379, + "dport": 53, + "src": "35.97.167.44", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "139", + "service_name": "Slack", + "master_protocol": "TLS", + "sport": 58695, + "dport": 443, + "src": "192.168.1.190", + "dst": "143.204.52.239", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "135", + "service_name": "UbuntuONE", + "master_protocol": "DNS", + "sport": 52351, + "dport": 53, + "src": "192.168.1.169", + "dst": "192.168.1.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "103", + "service_name": "Skype", + "master_protocol": "DNS", + "sport": 53519, + "dport": 53, + "src": "192.168.1.223", + "dst": "192.168.1.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "39", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 54990, + "dport": 80, + "src": "192.168.1.169", + "dst": "216.58.211.3", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "40", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 54988, + "dport": 80, + "src": "192.168.1.169", + "dst": "216.58.211.3", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "46", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 54986, + "dport": 80, + "src": "192.168.1.169", + "dst": "216.58.211.3", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "63", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 51871, + "dport": 443, + "src": "192.168.1.190", + "dst": "216.58.211.14", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "132", + "service_name": "ICMPV6", + "master_protocol": "Unknown", + "sport": 0, + "dport": 0, + "src": "140.242.122.109", + "dst": "189.93.205.231", + "proto": "58", + "alive": "1", + "active": false + }, + { + "flow_id": "45", + "service_name": "SSH", + "master_protocol": "Unknown", + "sport": 65192, + "dport": 22, + "src": "192.168.1.223", + "dst": "192.168.1.1", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "101", + "service_name": "Skype", + "master_protocol": "DNS", + "sport": 53519, + "dport": 53, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "114", + "service_name": "SSDP", + "master_protocol": "Unknown", + "sport": 57431, + "dport": 1900, + "src": "192.168.1.190", + "dst": "239.255.255.250", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "109", + "service_name": "Microsoft", + "master_protocol": "DNS", + "sport": 58229, + "dport": 53, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "96", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 58693, + "dport": 80, + "src": "192.168.1.190", + "dst": "8.8.8.8", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "129", + "service_name": "GoogleServices", + "master_protocol": "DNS", + "sport": 49308, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "9", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 59997, + "dport": 443, + "src": "192.168.1.223", + "dst": "3.9.202.151", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "16", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 60001, + "dport": 443, + "src": "192.168.1.223", + "dst": "3.9.202.151", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "100", + "service_name": "Skype", + "master_protocol": "DNS", + "sport": 59849, + "dport": 53, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "94", + "service_name": "SkypeCall", + "master_protocol": "STUN", + "sport": 13389, + "dport": 61850, + "src": "192.168.1.223", + "dst": "195.159.234.190", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "131", + "service_name": "GoogleServices", + "master_protocol": "DNS", + "sport": 51594, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "130", + "service_name": "GoogleServices", + "master_protocol": "DNS", + "sport": 52788, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "140", + "service_name": "Slack", + "master_protocol": "TLS", + "sport": 58696, + "dport": 443, + "src": "192.168.1.190", + "dst": "35.176.156.206", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "115", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 56772, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "126", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 56940, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "4", + "service_name": "CiscoVPN", + "master_protocol": "Unknown", + "sport": 58164, + "dport": 8009, + "src": "192.168.1.190", + "dst": "10.20.32.54", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "122", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 57160, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "5", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 443, + "dport": 51173, + "src": "64.233.165.189", + "dst": "192.168.1.190", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "86", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 443, + "dport": 65171, + "src": "20.185.212.106", + "dst": "192.168.1.223", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "98", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65201, + "dport": 443, + "src": "192.168.1.223", + "dst": "20.185.212.106", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "87", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 59955, + "dport": 443, + "src": "192.168.1.223", + "dst": "51.105.249.239", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "116", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 61762, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "23", + "service_name": "Google", + "master_protocol": "TLS", + "sport": 65102, + "dport": 443, + "src": "192.168.1.223", + "dst": "35.186.224.53", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "117", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 63080, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "124", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 64198, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "24", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 55022, + "dport": 80, + "src": "192.168.1.169", + "dst": "91.135.34.42", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "83", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65198, + "dport": 443, + "src": "192.168.1.223", + "dst": "52.114.158.20", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "110", + "service_name": "Microsoft", + "master_protocol": "TLS", + "sport": 65204, + "dport": 443, + "src": "192.168.1.223", + "dst": "52.114.158.91", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "136", + "service_name": "Slack", + "master_protocol": "DNS", + "sport": 50672, + "dport": 53, + "src": "35.97.167.44", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "7", + "service_name": "Google", + "master_protocol": "Unknown", + "sport": 58162, + "dport": 5228, + "src": "192.168.1.190", + "dst": "64.233.162.188", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "99", + "service_name": "Microsoft", + "master_protocol": "TLS", + "sport": 65202, + "dport": 443, + "src": "192.168.1.223", + "dst": "68.232.34.200", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "33", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 443, + "dport": 58169, + "src": "104.75.64.84", + "dst": "192.168.1.190", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "89", + "service_name": "Cloudflare", + "master_protocol": "HTTP", + "sport": 58691, + "dport": 80, + "src": "192.168.1.190", + "dst": "104.20.145.10", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "88", + "service_name": "DNS", + "master_protocol": "Unknown", + "sport": 57430, + "dport": 53, + "src": "35.97.167.44", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "138", + "service_name": "Slack", + "master_protocol": "DNS", + "sport": 58654, + "dport": 53, + "src": "35.97.167.44", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "42", + "service_name": "ICMPV6", + "master_protocol": "Unknown", + "sport": 0, + "dport": 0, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "58", + "alive": "1", + "active": false + }, + { + "flow_id": "97", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65200, + "dport": 443, + "src": "192.168.1.223", + "dst": "104.40.250.127", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "50", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 58674, + "dport": 443, + "src": "192.168.1.190", + "dst": "143.204.48.158", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "72", + "service_name": "SkypeCall", + "master_protocol": "STUN", + "sport": 13389, + "dport": 3478, + "src": "192.168.1.223", + "dst": "52.149.126.77", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "95", + "service_name": "SkypeCall", + "master_protocol": "STUN", + "sport": 13389, + "dport": 3480, + "src": "192.168.1.223", + "dst": "52.149.126.41", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "84", + "service_name": "Spotify", + "master_protocol": "Unknown", + "sport": 57621, + "dport": 57621, + "src": "192.168.1.223", + "dst": "192.168.1.255", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "58", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 65182, + "dport": 443, + "src": "192.168.1.223", + "dst": "143.204.48.158", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "71", + "service_name": "SkypeCall", + "master_protocol": "STUN", + "sport": 17391, + "dport": 3478, + "src": "192.168.1.223", + "dst": "52.137.56.8", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "73", + "service_name": "SkypeCall", + "master_protocol": "STUN", + "sport": 17391, + "dport": 3478, + "src": "192.168.1.223", + "dst": "52.149.125.240", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "35", + "service_name": "Dropbox", + "master_protocol": "Unknown", + "sport": 17500, + "dport": 17500, + "src": "192.168.1.190", + "dst": "255.255.255.255", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "26", + "service_name": "ICMPV6", + "master_protocol": "Unknown", + "sport": 0, + "dport": 0, + "src": "35.97.167.44", + "dst": "0.0.0.1", + "proto": "58", + "alive": "1", + "active": false + }, + { + "flow_id": "47", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 443, + "dport": 58625, + "src": "172.217.21.174", + "dst": "192.168.1.190", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "41", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 54989, + "dport": 80, + "src": "192.168.1.169", + "dst": "216.58.211.3", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "48", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 54987, + "dport": 80, + "src": "192.168.1.169", + "dst": "216.58.211.3", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "104", + "service_name": "Skype", + "master_protocol": "DNS", + "sport": 58856, + "dport": 53, + "src": "192.168.1.223", + "dst": "192.168.1.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "113", + "service_name": "Skype", + "master_protocol": "DNS", + "sport": 50150, + "dport": 53, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "108", + "service_name": "Microsoft", + "master_protocol": "DNS", + "sport": 54812, + "dport": 53, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "133", + "service_name": "ICMPV6", + "master_protocol": "Unknown", + "sport": 0, + "dport": 0, + "src": "140.242.122.109", + "dst": "226.158.40.91", + "proto": "58", + "alive": "1", + "active": false + }, + { + "flow_id": "22", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 443, + "dport": 58628, + "src": "3.9.202.151", + "dst": "192.168.1.190", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "102", + "service_name": "Skype", + "master_protocol": "DNS", + "sport": 58856, + "dport": 53, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "14", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 59998, + "dport": 443, + "src": "192.168.1.223", + "dst": "3.9.202.151", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "15", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 60000, + "dport": 443, + "src": "192.168.1.223", + "dst": "3.9.202.151", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "118", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 49929, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "128", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 52223, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "90", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 443, + "dport": 58683, + "src": "34.204.212.142", + "dst": "192.168.1.190", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "127", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 56945, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "6", + "service_name": "CiscoVPN", + "master_protocol": "Unknown", + "sport": 58165, + "dport": 8009, + "src": "192.168.1.190", + "dst": "10.20.32.42", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "111", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65174, + "dport": 443, + "src": "192.168.1.223", + "dst": "13.69.158.96", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "107", + "service_name": "DNS", + "master_protocol": "Unknown", + "sport": 57379, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "85", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 443, + "dport": 60033, + "src": "35.186.224.47", + "dst": "192.168.1.223", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "64", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65196, + "dport": 443, + "src": "192.168.1.223", + "dst": "20.185.212.106", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "134", + "service_name": "MDNS", + "master_protocol": "Unknown", + "sport": 5353, + "dport": 5353, + "src": "192.168.1.223", + "dst": "224.0.0.251", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "106", + "service_name": "DNS", + "master_protocol": "Unknown", + "sport": 60565, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "121", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 61629, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "112", + "service_name": "TLS", + "master_protocol": "Unknown", + "sport": 443, + "dport": 59948, + "src": "51.105.249.239", + "dst": "192.168.1.223", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "49", + "service_name": "ICMPV6", + "master_protocol": "Unknown", + "sport": 0, + "dport": 0, + "src": "140.242.122.109", + "dst": "35.97.167.44", + "proto": "58", + "alive": "1", + "active": false + }, + { + "flow_id": "125", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 64839, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "123", + "service_name": "Google", + "master_protocol": "DNS", + "sport": 65091, + "dport": 53, + "src": "226.158.40.91", + "dst": "0.0.0.1", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "17", + "service_name": "ICMPV6", + "master_protocol": "Unknown", + "sport": 0, + "dport": 0, + "src": "189.93.205.231", + "dst": "0.0.0.1", + "proto": "58", + "alive": "1", + "active": false + }, + { + "flow_id": "25", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 55021, + "dport": 80, + "src": "192.168.1.169", + "dst": "91.135.34.42", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "68", + "service_name": "Unknown", + "master_protocol": "Unknown", + "sport": 59198, + "dport": 3478, + "src": "192.168.1.223", + "dst": "52.114.158.14", + "proto": "17", + "alive": "1", + "active": false + }, + { + "flow_id": "78", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65197, + "dport": 443, + "src": "192.168.1.223", + "dst": "52.114.158.14", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "92", + "service_name": "Microsoft", + "master_protocol": "TLS", + "sport": 65199, + "dport": 443, + "src": "192.168.1.223", + "dst": "52.114.88.29", + "proto": "6", + "alive": "1", + "active": false + }, + { + "flow_id": "105", + "service_name": "Skype", + "master_protocol": "TLS", + "sport": 65203, + "dport": 443, + "src": "192.168.1.223", + "dst": "52.114.158.16", + "proto": "6", + "alive": "1", + "active": false + } + ] +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/side-test-pattern.json b/srcs/libs/docs/json_schema/json/side-test-pattern.json new file mode 100644 index 0000000..0424234 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/side-test-pattern.json @@ -0,0 +1,6 @@ +{ + "botenanna": "botenannna", + "boten": "boten", + "wuhu": "wublah", + "nullobject": null +} diff --git a/srcs/libs/docs/json_schema/json/side-test-patternProperties.json b/srcs/libs/docs/json_schema/json/side-test-patternProperties.json new file mode 100644 index 0000000..b7fbc0e --- /dev/null +++ b/srcs/libs/docs/json_schema/json/side-test-patternProperties.json @@ -0,0 +1,7 @@ +{ + "empty": {}, + "botenanna": { + "annaaaa": "boten" + }, + "nonobject": null +} diff --git a/srcs/libs/docs/json_schema/json/test-anyof.json b/srcs/libs/docs/json_schema/json/test-anyof.json new file mode 100644 index 0000000..8537a40 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-anyof.json @@ -0,0 +1,35 @@ +{ + "test-int": { + "id": 123 + }, + "test-double": { + "id": 1.23 + }, + "test-string": { + "id": "1234" + }, + "test-boolean": { + "id": true + }, + "test-array": [ + 123, + "1234" + ], + "test-array2": [ + 123, + {} + ], + "test-array": { + "anna": [ + { + "id": 1 + }, + { + "id": 2 + }, + { + "id": 3 + } + ] + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/test-enum.json b/srcs/libs/docs/json_schema/json/test-enum.json new file mode 100644 index 0000000..4376b17 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-enum.json @@ -0,0 +1,10 @@ +{ + "teststring1": "one", + "teststring2": "two", + "teststring3": "three", + "teststring4": "four", + "testinteger1": 1, + "testinteger2": 2, + "testinteger3": 3, + "testinteger4": 4 +} diff --git a/srcs/libs/docs/json_schema/json/test-items.json b/srcs/libs/docs/json_schema/json/test-items.json new file mode 100644 index 0000000..eb292e0 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-items.json @@ -0,0 +1,53 @@ +{ + "test1": { + "flowarray": [ + { + "key1": 5, + "key2": "hanz" + } + ] + }, + "wrongtype": { + "flowarray": [ + { + "key1": "5", + "key2": "hanz" + } + ] + }, + "missingkey": { + "flowarray": [ + { + "key2": "hanz" + } + ] + }, + "nestedarray": { + "flowarray": [ + { + "key1": "hanz", + "key2": [ + 1, + 2, + 3, + 4, + 5 + ] + } + ] + }, + "nestedarrayofstrings": { + "flowarray": [ + { + "key1": "hanz", + "key2": [ + "1", + "2", + "3", + "4", + "5" + ] + } + ] + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/test-maxmin-items.json b/srcs/libs/docs/json_schema/json/test-maxmin-items.json new file mode 100644 index 0000000..82bfa48 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-maxmin-items.json @@ -0,0 +1,7 @@ +{ + "array-1": [1], + "array-2": [1,2], + "array-3": [1,2,3], + "array-4": [1,2,3,4], + "array-5": [1,2,3,4,5] +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/test-properties.json b/srcs/libs/docs/json_schema/json/test-properties.json new file mode 100644 index 0000000..3c8dfbb --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-properties.json @@ -0,0 +1,57 @@ +{ + "emptyobject": {}, + + "testjson": { + "computer": "banana", + "phone": 12345678, + "switch": true + }, + + "testjsontrue": { + "computer": "banana", + "phone": 12345678, + "switch": true, + "object": {"object":123}, + "list": [1,2,3] + }, + + "testjsonfalse": { + "computer": 12345678, + "phone": "banana", + "switch": [1,2,3], + "object": true, + "list": {"object":123} + }, + + "testjsonstring-all": { + "computer1": "hansihansi", + "computer2": "hans", + "computer3": "ha", + "computer4": "han" + }, + + "testjsonstring-all-fail": { + "computer1": "hansihansi", + "computer2": "hansi", + "computer3": "han", + "computer4": "hans" + }, + + "testjsonstring2": { + "computer4": "ha" + }, + + "testjsonstring3": { + "computer4": "han" + }, + + "testjsonstring4": { + "computer4": "hans" + }, + + "testjsonstring5": { + "computer4": "hansp" + } + + +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/test-reqs-recursively.json b/srcs/libs/docs/json_schema/json/test-reqs-recursively.json new file mode 100644 index 0000000..07c1a68 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-reqs-recursively.json @@ -0,0 +1,36 @@ +{ + "alltrue": { + "person": { + "name": "Anna", + "husbands": 1 + } + }, + + "nametooshort": { + "person": { + "name": "Ann", + "husbands": 1 + } + }, + + "wrongtype": { + "person": { + "name": "Anna", + "husbands": "1" + } + }, + + "husbandmissing": { + "person": { + "name": "Anna" + } + }, + + "namemissing": { + "person": { + } + }, + + "empty": { + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/test-required.json b/srcs/libs/docs/json_schema/json/test-required.json new file mode 100644 index 0000000..b94951f --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-required.json @@ -0,0 +1,11 @@ +{ + "test-emptyjson": {}, + "test-keywords-abc": {"a":"a", "b":"b", "c":"c"}, + "test-keywords-bc": {"b":"b", "c":"c"}, + "test-keywords-ac": {"a":"a", "c":"c"}, + "test-keywords-ab": {"a":"a", "b":"b"}, + "test-keywords-a": {"a":"a"}, + "test-keywords-b": {"b":"b"}, + "test-keywords-c": {"c":"c"}, + "test-wrongtype": 123 +} diff --git a/srcs/libs/docs/json_schema/json/test-type.json b/srcs/libs/docs/json_schema/json/test-type.json new file mode 100644 index 0000000..46553e3 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-type.json @@ -0,0 +1,8 @@ +{ + "test-object" : {"1":"2"}, + "test-array" : [1,2,3], + "test-string" : "101", + "test-integer" : 101, + "test-double" : 101.1, + "test-boolean" : true +} diff --git a/srcs/libs/docs/json_schema/json/test-uniqueitems.json b/srcs/libs/docs/json_schema/json/test-uniqueitems.json new file mode 100644 index 0000000..919d1d1 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/test-uniqueitems.json @@ -0,0 +1,10 @@ +{ + "array-empty": [], + "array-unique1": [1,2,3,4,5,6], + "array-unique2": ["one","two","three"], + "array-notunique1": [1,2,3,3,5,6], + "array-notunique2": [1,2,3,4,5,5], + "array-notunique3": [1,1,3,4,5,6], + "array-notunique4": [1,1,1,4,5,6], + "array-notunique5": ["one", "two", "two"] +} diff --git a/srcs/libs/docs/json_schema/json/vectors-variants.json b/srcs/libs/docs/json_schema/json/vectors-variants.json new file mode 100644 index 0000000..01883e6 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/vectors-variants.json @@ -0,0 +1,106 @@ +{ +"truejson": + { + "ID": "lcss_vectors", + "Version": "v01", + "Services": [ + { + "Service": "slitherio", + "NetifyName": "gaming.slitherio", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ [444,445] ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [0,1], + "proto": "tcp", + "confidence": 10, + "vector": [1,2,3,4,5,6,7,8,9] + } + ] + } + ] + }, + + "validport_toohigh": + { + "ID": "lcss_vectors", + "Version": "v01", + "Services": [ + { + "Service": "slitherio", + "NetifyName": "gaming.slitherio", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ [444,445], [50000,100000] ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [0,1], + "proto": "tcp", + "confidence": 10, + "vector": [1,2,3,4,5,6,7,8,9] + } + ] + } + ] + }, + + "ignore_indices_index_too_high": + { + "ID": "lcss_vectors", + "Version": "v01", + "Services": [ + { + "Service": "slitherio", + "NetifyName": "gaming.slitherio", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ [444,445] ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [0,20], + "proto": "tcp", + "confidence": 10, + "vector": [1,2,3,4,5,6,7,8,9] + } + ] + } + ] + }, + + "too_many_vector_elements": + { + "ID": "lcss_vectors", + "Version": "v01", + "Services": [ + { + "Service": "slitherio", + "NetifyName": "gaming.slitherio", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ [444,445] ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [0,1], + "proto": "tcp", + "confidence": 10, + "vector": [0,1,2,3,4,5,6,7,8,9,10] + } + ] + } + ] + } + + } diff --git a/srcs/libs/docs/json_schema/json/vectors.json b/srcs/libs/docs/json_schema/json/vectors.json new file mode 100644 index 0000000..64f1f98 --- /dev/null +++ b/srcs/libs/docs/json_schema/json/vectors.json @@ -0,0 +1,760 @@ +{ + "ID": "lcss_vectors", + "Version": "v01", + "Services": [ + { + "Service": "slitherio", + "NetifyName": "gaming.slitherio", + "ValidPorts": [ + [ + 444, + 444 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [ + 0, + 1 + ], + "proto": "tcp", + "confidence": 10, + "vector": [ + 0, + 0 + ] + } + ] + }, + { + "Service": "steamworks", + "NetifyName": "gaming.steamworks", + "ValidPorts": [ + [ + 4380, + 4380 + ], + [ + 27000, + 27100 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 20, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 1300, + -214 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 1300, + 1300 + ] + } + ] + }, + { + "Service": "leagueoflegends", + "NetifyName": "gaming.leagueoflegends", + "ValidPorts": [ + [ + 5000, + 5500 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 515, + -107 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 515, + 515 + ] + } + ] + }, + { + "Service": "apex", + "NetifyName": "gaming.apex", + "ValidPorts": [ + [ + 1024, + 1124 + ], + [ + 18000, + 18000 + ], + [ + 29900, + 29900 + ], + [ + 37000, + 40000 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 50, + -58 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 50, + 50 + ] + } + ] + }, + { + "Service": "rainbow6", + "NetifyName": "gaming.rainbow6", + "ValidPorts": [ + [ + 3074, + 3074 + ], + [ + 4380, + 4380 + ], + [ + 6015, + 6015 + ], + [ + 10000, + 10099 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 139, + 139 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 139, + -131 + ] + } + ] + }, + { + "Service": "iperf3", + "NetifyName": "domos.iperf3", + "ValidPorts": [ + [ + 5201, + 5201 + ] + ], + "vectors": [ + { + "ID": "v2", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 4, + -4 + ] + } + ] + }, + { + "Service": "flent", + "NetifyName": "domos.flent", + "ValidPorts": [ + [ + 2116, + 2116 + ] + ], + "vectors": [ + { + "ID": "v2", + "ignore_indices": [], + "CT": 0, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 4, + -4 + ] + } + ] + }, + { + "Service": "unrealengine4", + "NetifyName": "gaming.unrealengine4", + "ValidPorts": [ + [ + 12000, + 65535 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 29, + -29 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 29, + 29 + ] + } + ] + }, + { + "Service": "overwatch", + "NetifyName": "gaming.overwatch", + "ValidPorts": [ + [ + 26400, + 27000 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 34, + -34 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 34, + 34 + ] + } + ] + }, + { + "Service": "valorant", + "NetifyName": "gaming.valorant", + "ValidPorts": [ + [ + 7000, + 7500 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 53, + -33 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 53, + 53 + ] + } + ] + }, + { + "Service": "seaofthieves", + "NetifyName": "gaming.seaofthieves", + "ValidPorts": [ + [ + 30000, + 32000 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 51, + -88 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 51, + 51 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 272, + 60 + ] + } + ] + }, + { + "Service": "rust", + "NetifyName": "gaming.rust", + "ValidPorts": [ + [ + 28015, + 28015 + ], + [ + 28225, + 28225 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 1372, + -28 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 1372, + 1372 + ] + } + ] + }, + { + "Service": "minecraft", + "NetifyName": "gaming.minecraft", + "ValidPorts": [ + [ + 19132, + 19133 + ], + [ + 19000, + 20000 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 33, + 1464 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 33, + 33 + ] + } + ] + }, + { + "Service": "gta5", + "NetifyName": "gaming.gta5", + "ValidPorts": [ + [ + 6672, + 6672 + ], + [ + 61455, + 61458 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 221, + 0 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 221, + -221 + ] + }, + { + "ID": "v3", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 237, + 0 + ] + }, + { + "ID": "v3", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 205, + 0 + ] + }, + { + "ID": "v3", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 141, + 205 + ] + } + ] + }, + { + "Service": "starcraft2", + "NetifyName": "gaming.starcraft2", + "ValidPorts": [ + [ + 3724, + 3724 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 20, + -20 + ] + }, + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 20, + 20 + ] + } + ] + }, + { + "Service": "video-conferencing", + "NetifyName": "video-conferencing.video-conf", + "ValidPorts": [ + [ + 3478, + 3478 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 4, + "vector": [] + } + ] + }, + { + "Service": "slack", + "NetifyName": "video-conferencing.slack", + "ValidPorts": [ + [ + 22466, + 22466 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "webex", + "NetifyName": "video-conferencing.webex", + "ValidPorts": [ + [ + 9000, + 9000 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "meet", + "NetifyName": "video-conferencing.meet", + "ValidPorts": [ + [ + 19302, + 19309 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "zoom", + "NetifyName": "video-conferencing.zoom", + "ValidPorts": [ + [ + 3478, + 3479 + ], + [ + 8801, + 8802 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "bluejeans", + "NetifyName": "video-conferencing.bluejeans", + "ValidPorts": [ + [ + 5000, + 5000 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "teams/skype", + "NetifyName": "video-conferencing.teams/skype", + "ValidPorts": [ + [ + 3478, + 3481 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/json/vectors2.json b/srcs/libs/docs/json_schema/json/vectors2.json new file mode 100644 index 0000000..6560cfa --- /dev/null +++ b/srcs/libs/docs/json_schema/json/vectors2.json @@ -0,0 +1,769 @@ +{ + "ID": "lcss_vectors", + "Version": "v01", + "Services": [ + { + "Service": "slitherio", + "NetifyName": "gaming.slitherio", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ + [ + 444, + 444 + ] + ], + "vectors": [ + { + "ID": "v0", + "TT": 0, + "ignore_indices": [ + 0, + 1 + ], + "proto": "tcp", + "confidence": 10, + "vector": [ + 0, + 0 + ] + } + ] + }, + { + "Service": "steamworks", + "NetifyName": "gaming.steamworks", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ + [ + 4380, + 4380 + ], + [ + 27000, + 27100 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 20, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 1300, + -214 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 1300, + 1300 + ] + } + ] + }, + { + "Service": "leagueoflegends", + "NetifyName": "gaming.leagueoflegends", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ + [ + 5000, + 5500 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 515, + -107 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 515, + 515 + ] + } + ] + }, + { + "Service": "apex", + "NetifyName": "gaming.apex", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ + [ + 1024, + 1124 + ], + [ + 18000, + 18000 + ], + [ + 29900, + 29900 + ], + [ + 37000, + 40000 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 50, + -58 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 50, + 50 + ] + } + ] + }, + { + "Service": "rainbow6", + "NetifyName": "gaming.rainbow6", + "max_diff": 1, + "max_length": 10, + "ValidPorts": [ + [ + 3074, + 3074 + ], + [ + 4380, + 4380 + ], + [ + 6015, + 6015 + ], + [ + 10000, + 10099 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 139, + 139 + ] + }, + { + "ID": "v1", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 139, + -131 + ] + } + ] + }, + { + "Service": "iperf3", + "NetifyName": "domos.iperf3", + "ValidPorts": [ + [ + 5201, + 5201 + ] + ], + "vectors": [ + { + "ID": "v2", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 4, + -4 + ] + } + ] + }, + { + "Service": "flent", + "NetifyName": "domos.flent", + "ValidPorts": [ + [ + 2116, + 2116 + ] + ], + "vectors": [ + { + "ID": "v2", + "ignore_indices": [], + "CT": 0, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 4, + -4 + ] + } + ] + }, + { + "Service": "unrealengine4", + "NetifyName": "gaming.unrealengine4", + "ValidPorts": [ + [ + 12000, + 65535 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 29, + -29 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 29, + 29 + ] + } + ] + }, + { + "Service": "overwatch", + "NetifyName": "gaming.overwatch", + "ValidPorts": [ + [ + 26400, + 27000 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 34, + -34 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 34, + 34 + ] + } + ] + }, + { + "Service": "valorant", + "NetifyName": "gaming.valorant", + "ValidPorts": [ + [ + 7000, + 7500 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 53, + -33 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 53, + 53 + ] + } + ] + }, + { + "Service": "seaofthieves", + "NetifyName": "gaming.seaofthieves", + "ValidPorts": [ + [ + 30000, + 32000 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 51, + -88 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 51, + 51 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 272, + 60 + ] + } + ] + }, + { + "Service": "rust", + "NetifyName": "gaming.rust", + "ValidPorts": [ + [ + 28015, + 28015 + ], + [ + 28225, + 28225 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 1372, + -28 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 1372, + 1372 + ] + } + ] + }, + { + "Service": "minecraft", + "NetifyName": "gaming.minecraft", + "ValidPorts": [ + [ + 19132, + 19133 + ], + [ + 19000, + 20000 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 33, + 1464 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 33, + 33 + ] + } + ] + }, + { + "Service": "gta5", + "NetifyName": "gaming.gta5", + "ValidPorts": [ + [ + 6672, + 6672 + ], + [ + 61455, + 61458 + ] + ], + "vectors": [ + { + "ID": "v0", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 221, + 0 + ] + }, + { + "ID": "v1", + "ignore_indices": [], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 221, + -221 + ] + }, + { + "ID": "v3", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 237, + 0 + ] + }, + { + "ID": "v3", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 205, + 0 + ] + }, + { + "ID": "v3", + "ignore_indices": [ + 1 + ], + "CT": 2, + "TT": 0, + "proto": "udp", + "confidence": 10, + "vector": [ + 141, + 205 + ] + } + ] + }, + { + "Service": "starcraft2", + "NetifyName": "gaming.starcraft2", + "ValidPorts": [ + [ + 3724, + 3724 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 20, + -20 + ] + }, + { + "ID": "v0", + "CT": 2, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 10, + "vector": [ + 20, + 20 + ] + } + ] + }, + { + "Service": "video-conferencing", + "NetifyName": "video-conferencing.video-conf", + "ValidPorts": [ + [ + 3478, + 3478 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 4, + "vector": [] + } + ] + }, + { + "Service": "slack", + "NetifyName": "video-conferencing.slack", + "ValidPorts": [ + [ + 22466, + 22466 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "webex", + "NetifyName": "video-conferencing.webex", + "ValidPorts": [ + [ + 9000, + 9000 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "meet", + "NetifyName": "video-conferencing.meet", + "ValidPorts": [ + [ + 19302, + 19309 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "zoom", + "NetifyName": "video-conferencing.zoom", + "ValidPorts": [ + [ + 3478, + 3479 + ], + [ + 8801, + 8802 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "bluejeans", + "NetifyName": "video-conferencing.bluejeans", + "ValidPorts": [ + [ + 5000, + 5000 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + }, + { + "Service": "teams/skype", + "NetifyName": "video-conferencing.teams/skype", + "ValidPorts": [ + [ + 3478, + 3481 + ] + ], + "vectors": [ + { + "ID": "v0", + "CT": 0, + "TT": 0, + "ignore_indices": [], + "proto": "udp", + "confidence": 6, + "vector": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/empty.json b/srcs/libs/docs/json_schema/schema/empty.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/empty.json @@ -0,0 +1 @@ +{} diff --git a/srcs/libs/docs/json_schema/schema/flows.json b/srcs/libs/docs/json_schema/schema/flows.json new file mode 100644 index 0000000..98a0796 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/flows.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Represents a collection of flows. For testing ref defs", + "type": "object", + "properties": { + "flows": { + "type": "array", + "items": { + "$ref": "#/$defs/flow" + } + } + }, + "required": [ + "flows" + ], + "$defs": { + "flow": { + "type": "object", + "properties": { + "flow_id": { + "type": "string" + }, + "service_name": { + "type": "string" + }, + "master_protocol": { + "type": "string" + }, + "sport": { + "type": "integer" + }, + "dport": { + "type": "integer" + }, + "src": { + "type": "string" + }, + "dst": { + "type": "string" + }, + "proto": { + "type": "string" + }, + "alive": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "extrakeythatdoesnotexist": { + "type": "string" + } + }, + "required": [ + "flow_id", + "service_name", + "master_protocol", + "sport", + "dport", + "src", + "dst", + "proto", + "alive", + "active" + ] + } + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/side-test-pattern.json b/srcs/libs/docs/json_schema/schema/side-test-pattern.json new file mode 100644 index 0000000..a007ed4 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/side-test-pattern.json @@ -0,0 +1,12 @@ +{ + "description": "string pattern side tests", + "schema-non-object": { + "pattern": true + }, + "schema-invalid-regex": { + "pattern": "^[a-zA-Z0-9]*@[a-zA-Z0-9-_.]*[.]*?" + }, + "schema-valid": { + "pattern": "boten*" + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/side-test-patternProperties.json b/srcs/libs/docs/json_schema/schema/side-test-patternProperties.json new file mode 100644 index 0000000..5a28e5b --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/side-test-patternProperties.json @@ -0,0 +1,23 @@ +{ + "description": "patternProperties side tests", + "schema-non-object": { + "patternProperties": true + }, + "schema-invalid-regex": { + "patternProperties": { + "^[a-zA-Z0-9]*@[a-zA-Z0-9-_.]*[.]*?": { + "type": "object" + } + } + }, + "schema-valid": { + "patternProperties": { + "boten*": { + "type": "string" + }, + "anna.*": { + "type": "string" + } + } + } +} diff --git a/srcs/libs/docs/json_schema/schema/test-anyof.json b/srcs/libs/docs/json_schema/schema/test-anyof.json new file mode 100644 index 0000000..303fb74 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-anyof.json @@ -0,0 +1,51 @@ +{ + "acceptstringandinteger": { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "anyOf": [ + { + "properties": { + "id": { + "type": "integer" + } + } + }, + { + "properties": { + "id": { + "type": "string" + } + } + } + ], + "required": [ + "id" + ] + }, + "inarray": { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "properties": { + "anna": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "required": [ + "id" + ] + } + ] + } + } + } + }, + "anyOfSchemaError": { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "type": "object", + "anyOf": [ + "type" + ] + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/test-enum.json b/srcs/libs/docs/json_schema/schema/test-enum.json new file mode 100644 index 0000000..5ef25f7 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-enum.json @@ -0,0 +1,22 @@ +{ + "enum-string": { + "type": "string", + "enum": [ + "one", + "two", + "three" + ] + }, + "enum-integer": { + "type": "integer", + "enum": [ + 1, + 2, + 3 + ] + }, + "enum-schemaerror": { + "type": "integer", + "enum": "1,2,3" + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/test-items.json b/srcs/libs/docs/json_schema/schema/test-items.json new file mode 100644 index 0000000..67ea610 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-items.json @@ -0,0 +1,51 @@ +{ + "test1": { + "type": "object", + "properties": { + "flowarray": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key1", + "key2" + ], + "properties": { + "key1": { + "type": "integer" + }, + "key2": { + "type": "string" + }, + } + } + } + } + }, + "nested": { + "type": "object", + "properties": { + "flowarray": { + "type": "array", + "items": { + "type": "object", + "required": [ + "key1", + "key2" + ], + "properties": { + "key1": { + "type": "string" + }, + "key2": { + "type": "array", + "items": { + "type": "integer" + } + }, + } + } + } + } + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/test-maxmin-items.json b/srcs/libs/docs/json_schema/schema/test-maxmin-items.json new file mode 100644 index 0000000..88d99d1 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-maxmin-items.json @@ -0,0 +1,7 @@ +{ + "schema-2-3": { + "type": "array", + "maxItems": 3, + "minItems": 2 + } +} diff --git a/srcs/libs/docs/json_schema/schema/test-properties.json b/srcs/libs/docs/json_schema/schema/test-properties.json new file mode 100644 index 0000000..e1567cd --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-properties.json @@ -0,0 +1,80 @@ +{ + "noproperties": + { + "type": "object" + }, + + "emptyproperties": + { + "type": "object", + "properties": {} + }, + + "typetests": + { + "type": "object", + "properties": { + "computer": { + "type": "string" + }, + "phone": { + "type": "integer" + }, + "switch": { + "type": "boolean" + }, + "object": { + "type": "object" + }, + "list": { + "type": "array" + } + } + }, + + "typetests2": + { + "type": "object", + "properties": { + "computer": { + "type": "string" + }, + "phone": { + "type": "integer" + }, + "switch": { + "type": "boolean" + }, + "object": { + "type": "object" + }, + "list": { + "type": "array" + } + } + }, + + "string-properties": + { + "type": "object", + "properties": { + "computer1": { + "type": "string" + }, + "computer2": { + "type": "string", + "maxLength": 4 + }, + "computer3": { + "type": "string", + "minLength": 2, + "maxLength": 2 + }, + "computer4": { + "type": "string", + "minLength": 3, + "maxLength": 4 + } + } + } +} diff --git a/srcs/libs/docs/json_schema/schema/test-reqs-recursively.json b/srcs/libs/docs/json_schema/schema/test-reqs-recursively.json new file mode 100644 index 0000000..ab69c08 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-reqs-recursively.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "properties": { + "person": { + "type": "object", + "properties": { + "name": {"type": "string", "minLength": 4}, + "husbands": {"type": "integer"} + }, + "required": ["name"] + } + }, + "required": ["person"] +} diff --git a/srcs/libs/docs/json_schema/schema/test-required.json b/srcs/libs/docs/json_schema/schema/test-required.json new file mode 100644 index 0000000..2be23af --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-required.json @@ -0,0 +1,12 @@ +{ + "test-emptyschema": {}, + "test-norequired": {"type": "object"}, + "test-required-empty": {"type": "object", "required": []}, + "test-require-abc": {"type": "object", "required": ["a","b","c"]}, + "test-require-bc": {"type": "object", "required": ["b","c"]}, + "test-require-ac": {"type": "object", "required": ["a","c"]}, + "test-require-ab": {"type": "object", "required": ["a","b"]}, + "test-require-a": {"type": "object", "required": ["a"]}, + "test-require-b": {"type": "object", "required": ["b"]}, + "test-require-c": {"type": "object", "required": ["c"]} +} diff --git a/srcs/libs/docs/json_schema/schema/test-type.json b/srcs/libs/docs/json_schema/schema/test-type.json new file mode 100644 index 0000000..f7754df --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-type.json @@ -0,0 +1,12 @@ +{ + "test-object" : {"type": "object"}, + "test-array" : {"type": "array"}, + "test-string" : {"type": "string"}, + "test-integer" : {"type": "integer"}, + "test-double" : {"type": "double"}, + "test-boolean" : {"type": "boolean"}, + "test-nonsense" : {"type": "nonsense"}, + "test-nonstring" : {"type": 1 }, + "test-nonstring2" : {"type": {"type": "yes" } } + } + \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/test-uniqueitems.json b/srcs/libs/docs/json_schema/schema/test-uniqueitems.json new file mode 100644 index 0000000..284c5e4 --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/test-uniqueitems.json @@ -0,0 +1,14 @@ +{ + "unique": { + "type": "array", + "uniqueItems": true + }, + "notunique": { + "type": "array", + "uniqueItems": false + }, + "schemaerror": { + "type": "array", + "uniqueItems": 1 + } +} \ No newline at end of file diff --git a/srcs/libs/docs/json_schema/schema/vectors.json b/srcs/libs/docs/json_schema/schema/vectors.json new file mode 100644 index 0000000..6558acc --- /dev/null +++ b/srcs/libs/docs/json_schema/schema/vectors.json @@ -0,0 +1,127 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "required": [ + "ID", + "Version", + "Services" + ], + "properties": { + "ID": { + "type": "string", + "enum": [ + "lcss_vectors" + ] + }, + "Version": { + "type": "string", + "minLength": 2 + }, + "Services": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "Service", + "NetifyName", + "ValidPorts", + "vectors" + ], + "properties": { + "Service": { + "type": "string", + "minLength": 4 + }, + "NetifyName": { + "type": "string", + "minLength": 4 + }, + "max_diff": { + "type": "integer" + }, + "max_length": { + "type": "integer" + }, + "ValidPorts": { + "type": "array", + "minItems": 1, + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "integer", + "minimum": 1, + "maximum": 65535 + } + } + }, + "vectors": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": [ + "ID", + "CT", + "TT", + "ignore_indices", + "proto", + "confidence", + "vector" + ], + "properties": { + "ID": { + "type": "string", + "enum": [ + "v0", + "v1", + "v2", + "v3" + ] + }, + "CT": { + "type": "integer", + "minimum": 0 + }, + "TT": { + "type": "integer", + "minimum": 0 + }, + "ignore_indices": { + "type": "array", + "maxItems": 10, + "items": { + "type": "integer", + "minimum": 0, + "maximum": 9 + } + }, + "proto": { + "type": "string", + "enum": [ + "tcp", + "udp" + ] + }, + "confidence": { + "type": "integer" + }, + "vector": { + "type": "array", + "maxItems": 10, + "items": { + "type": "integer", + "minimum": -1500, + "maximum": 1500 + } + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/srcs/libs/hardware/cpu.c b/srcs/libs/hardware/cpu.c index ae080ef..9502d91 100644 --- a/srcs/libs/hardware/cpu.c +++ b/srcs/libs/hardware/cpu.c @@ -20,7 +20,7 @@ typedef struct { #define CMD_CPU_CORE ("cat /proc/cpuinfo| grep \"cpu cores\" | uniq | awk \'{print $4}\'") #define CMP_CPU_LOGIC_CORE ("cat /proc/cpuinfo| grep \"cpu cores\" | wc -l") -#define SUM_CPU_TIME(x) ((x).user + (x).nice + (x).sys + (x).idle + (x).irq) +#define SUM_CPU_TIME(x) ((x).user + (x).nice + (x).sys + (x).idle + (x).irq) static int g_isInit = FALSE; static CPU_INFO g_cpuInfo; @@ -103,7 +103,7 @@ static int get_cpu_time_info(unsigned long *pTotal, unsigned long *pIdle) { *pTotal = *pIdle = 0; for (i = 0; i < nCpu; i++) { - *pIdle += pCpu[i].cpu_times.idle; + *pIdle += pCpu[i].cpu_times.idle; *pTotal += SUM_CPU_TIME(pCpu[i].cpu_times); } @@ -135,25 +135,7 @@ static void cpuUsedRefresh() { } } -_Noreturn void cpuCalcCb(void *UNUSED(pArg)) { - do { - unsigned int period = cfg_get_cpu_refresh_period(); - - if (cfg_get_watch_cpu()) { - cpuUsedRefresh(); - } - - if (period < REFRESH_MAX_PERIOD && period >= 1) { - uv_sleep(1000 * period); - } else { - uv_sleep(1000); - } - } while (TRUE); -} - int cpu_watch_init() { - static uv_thread_t uvThread; - memset(&g_cpuInfo, 0, sizeof(CPU_INFO)); g_cpuInfo.nCpus = get_cpu_number(); @@ -163,9 +145,6 @@ int cpu_watch_init() { get_cpu_desc(&g_cpuInfo.cpuCoreDesc); g_isInit = TRUE; - - uv_thread_create(&uvThread, cpuCalcCb, NULL); - return ERR_SUCCESS; } @@ -184,6 +163,8 @@ int get_cpu_info(PCPU_INFO pInfo) { get_cpu_desc(&g_cpuInfo.cpuCoreDesc); g_isInit = TRUE; + } else if (cfg_get_watch_cpu()) { + cpuUsedRefresh(); } memcpy(pInfo, &g_cpuInfo, sizeof(CPU_INFO)); diff --git a/srcs/libs/hardware/disk.c b/srcs/libs/hardware/disk.c index c5fee99..da61056 100644 --- a/srcs/libs/hardware/disk.c +++ b/srcs/libs/hardware/disk.c @@ -12,7 +12,7 @@ #include "uthash/uthash.h" #include "config.h" -#define MAX_SIZE_LEN (16) +#define MAX_SIZE_LEN (16) //#define CMD_DISK_FILESYSTEM ("df -h | awk \'{if (NR > 1){print $0}}\'") #define CMD_DISK_FILESYSTEM ("df -h | awk \'{if (NR > 1){print $1\"|\"$2\"|\"$3\"|\"$4\"|\"$5\"|\"$6}}\'") @@ -105,6 +105,10 @@ int get_disk_info(PDISK_INFO pInfo) { return -ERR_INPUT_PARAMS; } + if (cfg_get_watch_disk()) { + disk_info_refresh(); + } + uv_rwlock_rdlock(&g_uvLock); pInfo->nItems = HASH_COUNT(g_diskPartInfo); pInfo->timestamp = time(NULL); @@ -122,32 +126,12 @@ int get_disk_info(PDISK_INFO pInfo) { return ERR_SUCCESS; } -_Noreturn void diskRefreshCb(void *UNUSED(pArg)) { - do { - unsigned int period = cfg_get_disk_refresh_period(); - - if (cfg_get_watch_disk()) { - disk_info_refresh(); - } - - if (period < REFRESH_MAX_PERIOD && period >= 1) { - uv_sleep(1000 * period); - } else { - uv_sleep(1000); - } - } while (TRUE); -} - int disk_watch_info() { - static uv_thread_t uvThread; - uv_rwlock_init(&g_uvLock); if (disk_info_refresh() != ERR_SUCCESS) { return -ERR_SYS_DISK_GET_INFO; } - uv_thread_create(&uvThread, diskRefreshCb, NULL); - return ERR_SUCCESS; } \ No newline at end of file diff --git a/srcs/libs/hardware/hardware.c b/srcs/libs/hardware/hardware.c index cafa018..3f12302 100644 --- a/srcs/libs/hardware/hardware.c +++ b/srcs/libs/hardware/hardware.c @@ -9,51 +9,48 @@ #include "user_errno.h" #include "config.h" #include "misc.h" +#include "task_manager.h" static HARDWARE_INFO g_hardwareInfo; -_Noreturn void hardwareRefreshCb(void *UNUSED(pArg)) { - do { - unsigned int period = cfg_get_hardware_refresh_period(); +void hardwareRefreshCb(uv_timer_t *UNUSED(pArg)) { + if (cfg_get_watch_sensor()) { + get_sensor_info(&g_hardwareInfo.sensorInfo); + } + if (cfg_get_watch_disk()) { + get_disk_info(&g_hardwareInfo.diskInfo); + } + if (cfg_get_watch_cpu()) { + get_cpu_info(&g_hardwareInfo.cpuInfo); + } + if (cfg_get_watch_memory()) { + get_memory_info(&g_hardwareInfo.memInfo); + } - if (cfg_get_watch_sensor()) { - get_sensor_info(&g_hardwareInfo.sensorInfo); - } - - if (cfg_get_watch_disk()) { - get_disk_info(&g_hardwareInfo.diskInfo); - } - - if (cfg_get_watch_cpu()) { - get_cpu_info(&g_hardwareInfo.cpuInfo); - } - - if (cfg_get_watch_memory()) { - get_memory_info(&g_hardwareInfo.memInfo); - } - - if (period < REFRESH_MAX_PERIOD && period >= 1) { - uv_sleep(1000 * period); - } else { - uv_sleep(1000); - } - - uv_sleep(1000); - } while (TRUE); + //printf("%s\n", get_hardware_json()); } int init_hardware() { - static uv_thread_t uvThread; + static uv_timer_t uvTm; + unsigned int period = cfg_get_hardware_refresh_period(); + + if (period >= REFRESH_MAX_PERIOD) { + period = 10000; + } else { + period *= 1000; + } + + uv_timer_init(get_task_manager(), &uvTm); memset(&g_hardwareInfo, 0, sizeof(HARDWARE_INFO)); - uv_thread_create(&uvThread, hardwareRefreshCb, NULL); - cpu_watch_init(); memory_watch_init(); disk_watch_info(); sensor_watch_init(); + uv_timer_start(&uvTm, hardwareRefreshCb, period, period); + return ERR_SUCCESS; } diff --git a/srcs/libs/hardware/ipmltools.c b/srcs/libs/hardware/ipmltools.c index 57bb077..13b84b3 100644 --- a/srcs/libs/hardware/ipmltools.c +++ b/srcs/libs/hardware/ipmltools.c @@ -12,10 +12,11 @@ #include "misc.h" #include "config.h" -#define MAX_SENSOR_STR (32) +#define MAX_SENSOR_STR (32) //#define CMD_SENSOR_INFO ("ipmitool sensor | awk '{gsub(/\|/, \"\"); print $0}'") -#define CMD_SENSOR_INFO ("ipmitool sensor") +#define CMD_SENSOR_INFO ("ipmitool sensor") +#define CMD_IPMITOOL_ENABLE ("whereis ipmitool | awk '{print $2}'") typedef struct { char name[MAX_SENSOR_STR]; ///< 传感器名称 @@ -42,9 +43,16 @@ static int sensor_info_refresh() { int errCode = ERR_SUCCESS; FILE *fp; char buf[1024]; + char *pRet = NULL; + + if (shell_with_output(CMD_IPMITOOL_ENABLE, &pRet) != ERR_SUCCESS || pRet == NULL || strlen(pRet) == 0) { + if (pRet) { + free(pRet); + } + return -ERR_ITEM_UNEXISTS; + } fp = popen(CMD_SENSOR_INFO, "r"); - if (fp == NULL) { return -ERR_OPEN_FILE; } @@ -132,6 +140,10 @@ int get_sensor_info(PSENSOR_INFO pInfo) { return -ERR_INPUT_PARAMS; } + if (cfg_get_watch_sensor()) { + sensor_info_refresh(); + } + uv_rwlock_rdlock(&g_uvLock); pInfo->nItems = HASH_COUNT(g_pSensorInfo); pInfo->timestamp = time(NULL); @@ -149,27 +161,9 @@ int get_sensor_info(PSENSOR_INFO pInfo) { return ERR_SUCCESS; } -_Noreturn void sensorRefreshCb(void *UNUSED(pArg)) { - do { - unsigned int period = cfg_get_sensor_refresh_period(); - - if (cfg_get_watch_sensor()) { - sensor_info_refresh(); - } - - if (period < REFRESH_MAX_PERIOD && period >= 1) { - uv_sleep(1000 * period); - } else { - uv_sleep(1000); - } - } while (TRUE); -} - int sensor_watch_init() { - - static uv_thread_t uvThread; - int i, devOk = FALSE; - int n = ARRAY_SIZE(g_ipmiDev); + int i, devOk = FALSE; + int n = ARRAY_SIZE(g_ipmiDev); uv_rwlock_init(&g_uvLock); @@ -188,7 +182,5 @@ int sensor_watch_init() { return -ERR_SYS_SENSOR_GET_INFO; } - uv_thread_create(&uvThread, sensorRefreshCb, NULL); - return ERR_SUCCESS; } \ No newline at end of file diff --git a/srcs/libs/hardware/memory.c b/srcs/libs/hardware/memory.c index 5d5cc9a..e777a1a 100644 --- a/srcs/libs/hardware/memory.c +++ b/srcs/libs/hardware/memory.c @@ -14,11 +14,11 @@ #define CMD_MEMORY_INFO ("cat /proc/meminfo | awk \'{print $1\"|\"$2\"|\"$3}\'") -#define M_SIZE (1024 * 1024) +#define M_SIZE (1024 * 1024) -#define KEY_NAME (32) -#define KEY_VALUE (32) -#define VALUE_UNIT (8) +#define KEY_NAME (32) +#define KEY_VALUE (32) +#define VALUE_UNIT (8) typedef struct { char itemName[KEY_NAME]; @@ -95,33 +95,13 @@ static int memory_info_refresh() { return errCode; } -_Noreturn void memRefreshCb(void *UNUSED(pArg)) { - do { - unsigned int period = cfg_get_mem_refresh_period(); - - if (cfg_get_watch_memory()) { - memory_info_refresh(); - } - - if (period < REFRESH_MAX_PERIOD && period >= 1) { - uv_sleep(1000 * period); - } else { - uv_sleep(1000); - } - } while (TRUE); -} - int memory_watch_init() { - static uv_thread_t uvThread; - uv_rwlock_init(&g_uvLock); if (memory_info_refresh() != ERR_SUCCESS) { return -ERR_SYS_DISK_GET_INFO; } - uv_thread_create(&uvThread, memRefreshCb, NULL); - return ERR_SUCCESS; } @@ -142,6 +122,10 @@ int get_memory_info(PMEMORY_INFO pInfo) { return -ERR_INPUT_PARAMS; } + if (cfg_get_watch_memory()) { + memory_info_refresh(); + } + uv_rwlock_rdlock(&g_uvLock); for (i = 0; i < n; i++) { diff --git a/srcs/libs/include/config.h b/srcs/libs/include/config.h index 8d8f40b..687e981 100644 --- a/srcs/libs/include/config.h +++ b/srcs/libs/include/config.h @@ -41,10 +41,6 @@ typedef enum { CFG_WATCH_MEMORY, CFG_WATCH_DISK, CFG_WATCH_SENSOR, - CFG_CPU_REFRESH, - CFG_MEM_REFRESH, - CFG_DISK_REFRESH, - CFG_SENSOR_REFRESH, #ifdef USED_REDIS CFG_DB_REDIS_SERVER, CFG_DB_REDIS_PORT, @@ -61,8 +57,10 @@ typedef enum { CFG_DB_SQLITE_DB_NAME, CFG_DB_SQLITE_PASSWD, #endif +#ifdef ZEROMQ_ON CFG_MQ_SVR_PORT, CFG_MQ_DATA_PATH, +#endif CFG_VXLAN_NIC_NAME, CFG_VXLAN_SUPPORT, CFG_VXLAN_PEER_IP, @@ -92,10 +90,6 @@ int cfg_get_watch_cpu(); int cfg_get_watch_memory(); int cfg_get_watch_disk(); int cfg_get_watch_sensor(); -unsigned int cfg_get_cpu_refresh_period(); -unsigned int cfg_get_mem_refresh_period(); -unsigned int cfg_get_disk_refresh_period(); -unsigned int cfg_get_sensor_refresh_period(); #ifdef USED_REDIS const char *cfg_get_redis_server(); int cfg_get_redis_port(); @@ -112,8 +106,10 @@ const char *cfg_get_mysql_database(); const char *cfg_get_sqlite_db_name(); const char *cfg_get_sqlite_passwd(); #endif +#ifdef ZEROMQ_ON int cfg_get_zero_mq_port(); const char *cfg_get_zero_mq_data_path(); +#endif const char *cfg_get_string_value(CONFIG_ITEM_ID id); c_vector cfg_get_vector(CONFIG_ITEM_ID id); diff --git a/srcs/libs/include/json_schema/internal.h b/srcs/libs/include/json_schema/internal.h new file mode 100644 index 0000000..9f92388 --- /dev/null +++ b/srcs/libs/include/json_schema/internal.h @@ -0,0 +1,26 @@ +#ifndef __INTERNAL_H +#define __INTERNAL_H + +#include + +int _jdac_load(const char *jsonfile, const char *jsonschema); +int __jdac_inspect_type(json_object *jobj, const char *type); +int _jdac_check_type (json_object *jobj, json_object *jschema); +int _jdac_check_required (json_object *jobj, json_object *jschema); +int _jdac_check_properties (json_object *jobj, json_object *jschema); +int _jdac_check_prefixItems_and_items (json_object *jobj, json_object *jschema); +int _jdac_value_is_equal (json_object *jobj1, json_object *jobj2); +int _jdac_check_const (json_object *jobj, json_object *jschema); +int _jdac_check_enums (json_object *jobj, json_object *jschema); +int _jdac_check_uniqueItems (json_object *jobj, json_object *jschema); +int _jdac_check_maxmin_items (json_object *jobj, json_object *jschema); +int _jdac_validate_array (json_object *jobj, json_object *jschema); +int _jdac_validate_object (json_object *jobj, json_object *jschema); +int _jdac_validate_string (json_object *jobj, json_object *jschema); +int _jdac_validate_integer (json_object *jobj, json_object *jschema); +int _jdac_validate_double (json_object *jobj, json_object *jschema); +int _jdac_validate_number (json_object *jobj, json_object *jschema, double value); +int _jdac_validate_boolean (json_object *jobj, json_object *jschema); +int _jdac_validate_instance (json_object *jobj, json_object *jschema); + +#endif // __INTERNAL_H diff --git a/srcs/libs/include/json_schema/jsoncdaccord.h b/srcs/libs/include/json_schema/jsoncdaccord.h new file mode 100644 index 0000000..8ef0700 --- /dev/null +++ b/srcs/libs/include/json_schema/jsoncdaccord.h @@ -0,0 +1,40 @@ +#ifndef __JSONCDACCORD_H +#define __JSONCDACCORD_H + +#include + +enum jdac_errors { + JDAC_ERR_VALID = 0, + JDAC_ERR_GENERAL_ERROR, + JDAC_ERR_JSON_NOT_FOUND, + JDAC_ERR_SCHEMA_NOT_FOUND, + JDAC_ERR_WRONG_ARGS, + JDAC_ERR_SCHEMA_ERROR, + JDAC_ERR_INVALID, + JDAC_ERR_INVALID_TYPE, + JDAC_ERR_INVALID_REQUIRED, + JDAC_ERR_INVALID_SUBSCHEMALOGIC, + JDAC_ERR_INVALID_CONST, + JDAC_ERR_INVALID_ENUMS, + JDAC_ERR_INVALID_STRLEN, + JDAC_ERR_INVALID_UNIQUEITEMS, + JDAC_ERR_INVALID_PREFIXITEMS, + JDAC_ERR_INVALID_ITEMS, + JDAC_ERR_INVALID_CONTAINS, + JDAC_ERR_INVALID_ARRAYLEN, + JDAC_ERR_INVALID_NUMBER, + JDAC_ERR_INVALID_PATTERNMATCH, + JDAC_ERR_INVALID_REF, + JDAC_REGEX_MISMATCH, + JDAC_REGEX_MATCH, + JDAC_REGEX_COMPILE_FAILED, + JDAC_ERR_MAX +}; + +int jdac_validate_file(const char *jsonfile, const char *jsonschemafile); +int jdac_validate(json_object *jobj, json_object *jschema); +int jdac_ref_set_localpath(const char *_localpath); + +const char *jdac_errorstr(unsigned int jdac_errors); + +#endif //__JSONCDACCORD_H diff --git a/srcs/libs/include/json_schema/optional.h b/srcs/libs/include/json_schema/optional.h new file mode 100644 index 0000000..5b2c968 --- /dev/null +++ b/srcs/libs/include/json_schema/optional.h @@ -0,0 +1,36 @@ +#ifndef __OPTIONAL_H +#define __OPTIONAL_H + +#include + +typedef struct storage_node { + char JSONPtrURI[128]; + char id[128]; + char anchor[32]; + char dynamicAnchor[32]; + json_object *json_instance_ptr; + json_object *json_schema_ptr; + int is_root; + struct storage_node *next; +} storage_node; + +int _jdac_match_string_with_regex(const char* regex_pattern, const char* value); +int _jdac_check_pattern(json_object *jobj, json_object *jschema); +int _jdac_check_patternproperties(json_object *jobj, json_object *jschema); +int _jdac_check_additionalproperties(json_object *jobj, json_object *jschema); +int _jdac_check_propertynames(json_object *jobj, json_object *jschema); +int _jdac_check_subschemalogic(json_object *jobj, json_object *jschema); +int _jdac_check_contains_and_minmaxcontains(json_object *jobj, json_object *jschema); + +char* _jdac_download_schema(const char *url); +const char* _jdac_download_resolve(const char *uri); + +int _jdac_store_traverse_json(storage_node **head, json_object *jschema, char *pathbuffer); +void _jdac_store_free(storage_node **head); +void _jdac_store_print(storage_node *head); +json_object* _jdac_store_resolve(storage_node *list, const char *uri); +storage_node* _jdac_store_get_root_node(storage_node *head); + +int _jdac_check_ref(json_object *jobj, json_object *jschema, storage_node *storage_list); + +#endif // __OPTIONAL_H diff --git a/srcs/libs/include/misc.h b/srcs/libs/include/misc.h index de22005..0477ea5 100644 --- a/srcs/libs/include/misc.h +++ b/srcs/libs/include/misc.h @@ -61,6 +61,8 @@ int get_nic_info(const char *pName, unsigned char *pMac); int str_to_ipaddr(const char *pIp, unsigned int *ipAddr); unsigned long long get_current_time_ms(); +int process_lock_pidfile(char *pFilePath); +void process_unlock_pidfile(); #ifdef __cplusplus } #endif diff --git a/srcs/libs/include/proto.h b/srcs/libs/include/proto.h index 89cf5e8..33fbc4a 100644 --- a/srcs/libs/include/proto.h +++ b/srcs/libs/include/proto.h @@ -18,8 +18,9 @@ typedef enum { CRYPTO_AES256 = 4, } PROTO_CRYPTO_TYPE; +const char *proto_msg_validation(const char *pJsonStr, const char *msgJson, const char *errMsg); const char *proto_create_new(cJSON *pMsgCtx, int httpCode); -const char *proto_decode_context(const char *pString, unsigned int *pVer, unsigned long long *pTm); +const char *proto_decode_context(const char *pString, unsigned int *pVer, unsigned long long *pTm, int *pErrCode); #ifdef __cplusplus } #endif diff --git a/srcs/libs/include/user_errno.h b/srcs/libs/include/user_errno.h index a76a3d7..d474216 100644 --- a/srcs/libs/include/user_errno.h +++ b/srcs/libs/include/user_errno.h @@ -8,8 +8,6 @@ extern "C" { #endif -#define USED_USER_ERRNO - #define DEF_ERR_CODE(ERR_CODE) \ ERR_CODE(ERR_SUCCESS, 0, "成功") \ ERR_CODE(ERR_INPUT_PARAMS, 1, "输入参数错误") \ @@ -21,48 +19,49 @@ extern "C" { ERR_CODE(ERR_OPEN_FILE, 7, "打开文件失败") \ ERR_CODE(ERR_READ_FILE, 8, "读取文件失败") \ ERR_CODE(ERR_FILE_NOT_EXISTS, 9, "文件不存在") \ - ERR_CODE(ERR_GET_FILE_SIZE, 10, "获取文件大小失败") \ - ERR_CODE(ERR_COPY_FILE, 11, "复制文件失败") \ - ERR_CODE(ERR_MALLOC_MEMORY, 12, "分配内存失败") \ - ERR_CODE(ERR_EVP_KEY_SIZE, 13, "秘钥大小不正确") \ - ERR_CODE(ERR_UNSUP_EVP_TYPE, 14, "不支持的加解密算法") \ - ERR_CODE(ERR_EVP_INIT_KEY, 15, "初始化秘钥失败") \ - ERR_CODE(ERR_EVP_UPDATE, 16, "加解密数据失败") \ - ERR_CODE(ERR_EVP_FINALE, 17, "错误的加解密结果") \ - ERR_CODE(ERR_EVP_CREATE_CTX, 18, "初始化加解密失败") \ - ERR_CODE(ERR_AES128_KEYGEN, 19, "AES128秘钥失败") \ - ERR_CODE(ERR_EVP_ENCRYPTION, 20, "加密失败") \ - ERR_CODE(ERR_EVP_DECRYPTION, 21, "解密失败") \ - ERR_CODE(ERR_CONFIG_INIT, 22, "配置文件初始化失败") \ - ERR_CODE(ERR_UNCOMPATIBILITY_TYPE, 23, "未兼容的类型") \ - ERR_CODE(ERR_STRING_TO_NUMBER, 24, "字符串转数字失败") \ - ERR_CODE(ERR_UNKNOWN_CFG_ID, 25, "未识别的配置项") \ - ERR_CODE(ERR_ZLOG_INIT, 26, "日志系统初始化失败") \ - ERR_CODE(ERR_SYS_GET_CPU_INFO, 27, "获取CPU信息失败") \ - ERR_CODE(ERR_SYS_NOT_FOUND_CPU, 28, "找不到CPU信息") \ - ERR_CODE(ERR_SYS_DISK_GET_INFO, 29, "获取磁盘空间占用信息失败") \ - ERR_CODE(ERR_SYS_IPMI_UNSUP, 30, "服务器IPMI接口不支持") \ - ERR_CODE(ERR_SYS_SENSOR_GET_INFO, 31, "获取传感器信息失败") \ - ERR_CODE(ERR_DB_CONNECT, 32, "数据库连接失败") \ - ERR_CODE(ERR_MQ_CREATE_MQ, 33, "创建消息队列失败") \ - ERR_CODE(ERR_MQ_CREATE_REP, 34, "创建REP消息队列失败") \ - ERR_CODE(ERR_MQ_BIND_SOCKET, 35, "消息队列BIND Socket失败") \ - ERR_CODE(ERR_MQ_CONN_SERVER, 36, "消息队列连接服务器失败") \ - ERR_CODE(ERR_MQ_SEND_MSG, 37, "消息队列发送消息失败") \ - ERR_CODE(ERR_JSON_CREAT_OBJ, 38, "创建JSON对象失败") \ - ERR_CODE(ERR_JSON_PRASE_OBJ, 39, "解析JSON对象失败") \ - ERR_CODE(ERR_CREATE_NETIF, 40, "创建网络接口失败") \ - ERR_CODE(ERR_CREATE_PPPOE_NETIF, 41, "创建PPPoE网络接口失败") \ - ERR_CODE(ERR_CREATE_PPP_SESSION, 42, "创建PPP连接失败") \ - ERR_CODE(ERR_MISC_GET_IPADDR, 43, "获取网卡IP地址失败") \ - ERR_CODE(ERR_MISC_GET_NETMASK, 44, "获取网卡子网掩码失败") \ - ERR_CODE(ERR_MISC_GET_GATEWAY, 45, "获取网卡网关地址失败") \ - ERR_CODE(ERR_MISC_GET_MACADDR, 46, "获取网卡MAC地址失败") \ - ERR_CODE(ERR_MENU_EXIT, 47, "菜单执行完后自动退出") \ - ERR_CODE(ERR_HTTP_UNSUP_METHOD, 48, "不支持的 HTTP 请求方法") \ - ERR_CODE(ERR_HTTP_UNSUP_PAGE, 49, "找不到 HTTP 服务") \ - ERR_CODE(ERR_PROTO_DECODE, 50, "HTTP 协议解析失败") - + ERR_CODE(ERR_FILE_LOCKED, 10, "文件被锁定") \ + ERR_CODE(ERR_GET_FILE_SIZE, 11, "获取文件大小失败") \ + ERR_CODE(ERR_COPY_FILE, 12, "复制文件失败") \ + ERR_CODE(ERR_MALLOC_MEMORY, 13, "分配内存失败") \ + ERR_CODE(ERR_EVP_KEY_SIZE, 14, "秘钥大小不正确") \ + ERR_CODE(ERR_UNSUP_EVP_TYPE, 15, "不支持的加解密算法") \ + ERR_CODE(ERR_EVP_INIT_KEY, 16, "初始化秘钥失败") \ + ERR_CODE(ERR_EVP_UPDATE, 17, "加解密数据失败") \ + ERR_CODE(ERR_EVP_FINALE, 18, "错误的加解密结果") \ + ERR_CODE(ERR_EVP_CREATE_CTX, 19, "初始化加解密失败") \ + ERR_CODE(ERR_AES_KEYGEN, 20, "AES秘钥失败") \ + ERR_CODE(ERR_EVP_ENCRYPTION, 21, "加密失败") \ + ERR_CODE(ERR_EVP_DECRYPTION, 22, "解密失败") \ + ERR_CODE(ERR_CONFIG_INIT, 23, "配置文件初始化失败") \ + ERR_CODE(ERR_UNCOMPATIBILITY_TYPE, 24, "未兼容的类型") \ + ERR_CODE(ERR_STRING_TO_NUMBER, 25, "字符串转数字失败") \ + ERR_CODE(ERR_UNKNOWN_CFG_ID, 26, "未识别的配置项") \ + ERR_CODE(ERR_ZLOG_INIT, 27, "日志系统初始化失败") \ + ERR_CODE(ERR_SYS_GET_CPU_INFO, 28, "获取CPU信息失败") \ + ERR_CODE(ERR_SYS_NOT_FOUND_CPU, 29, "找不到CPU信息") \ + ERR_CODE(ERR_SYS_DISK_GET_INFO, 30, "获取磁盘空间占用信息失败") \ + ERR_CODE(ERR_SYS_IPMI_UNSUP, 31, "服务器IPMI接口不支持") \ + ERR_CODE(ERR_SYS_SENSOR_GET_INFO, 32, "获取传感器信息失败") \ + ERR_CODE(ERR_DB_CONNECT, 33, "数据库连接失败") \ + ERR_CODE(ERR_MQ_CREATE_MQ, 34, "创建消息队列失败") \ + ERR_CODE(ERR_MQ_CREATE_REP, 35, "创建REP消息队列失败") \ + ERR_CODE(ERR_MQ_BIND_SOCKET, 36, "消息队列BIND Socket失败") \ + ERR_CODE(ERR_MQ_CONN_SERVER, 37, "消息队列连接服务器失败") \ + ERR_CODE(ERR_MQ_SEND_MSG, 38, "消息队列发送消息失败") \ + ERR_CODE(ERR_JSON_CREAT_OBJ, 39, "创建JSON对象失败") \ + ERR_CODE(ERR_JSON_PARSE_OBJ, 40, "解析JSON对象失败") \ + ERR_CODE(ERR_JSON_VALID_SCH, 41, "JSON数据验证失败") \ + ERR_CODE(ERR_CREATE_NETIF, 42, "创建网络接口失败") \ + ERR_CODE(ERR_CREATE_PPPOE_NETIF, 43, "创建PPPoE网络接口失败") \ + ERR_CODE(ERR_CREATE_PPP_SESSION, 44, "创建PPP连接失败") \ + ERR_CODE(ERR_MISC_GET_IPADDR, 45, "获取网卡IP地址失败") \ + ERR_CODE(ERR_MISC_GET_NETMASK, 46, "获取网卡子网掩码失败") \ + ERR_CODE(ERR_MISC_GET_GATEWAY, 47, "获取网卡网关地址失败") \ + ERR_CODE(ERR_MISC_GET_MACADDR, 48, "获取网卡MAC地址失败") \ + ERR_CODE(ERR_MENU_EXIT, 49, "菜单执行完后自动退出") \ + ERR_CODE(ERR_HTTP_UNSUP_METHOD, 50, "不支持的 HTTP 请求方法") \ + ERR_CODE(ERR_HTTP_UNSUP_PAGE, 51, "找不到 HTTP 服务") \ + ERR_CODE(ERR_PROTO_DECODE, 52, "HTTP 协议解析失败") #define GENERATE_ENUM(ENUM, no, x) ENUM, typedef enum { diff --git a/srcs/libs/include/zlog_module.h b/srcs/libs/include/zlog_module.h index 6a7b582..27c7ff8 100644 --- a/srcs/libs/include/zlog_module.h +++ b/srcs/libs/include/zlog_module.h @@ -34,7 +34,8 @@ typedef enum { ZLOG_MOD(ZLOG_MOD_CRYPTO, ZLOG_LEVEL_DEBUG, "CRYPTO") \ ZLOG_MOD(ZLOG_MOD_MQ, ZLOG_LEVEL_DEBUG, "MQ") \ ZLOG_MOD(ZLOG_MOD_PROTO, ZLOG_LEVEL_DEBUG, "PROTO") \ - ZLOG_MOD(ZLOG_MOD_HTTPD, ZLOG_LEVEL_INFO, "HTTPD") \ + ZLOG_MOD(ZLOG_MOD_HTTPD, ZLOG_LEVEL_INFO, "HTTPD") \ + ZLOG_MOD(ZLOG_MOD_JSCHEM, ZLOG_LEVEL_INFO, "JSCHEM") \ ZLOG_MOD(ZLOG_MOD_USER, ZLOG_LEVEL_DEBUG, "USER") \ ZLOG_MOD(ZLOG_MOD_PPPOE, ZLOG_LEVEL_DEBUG, "PPPOE") \ ZLOG_MOD(ZLOG_MOD_VXLAN, ZLOG_LEVEL_DEBUG, "VXLAN") \ @@ -64,6 +65,9 @@ typedef enum { #define LOG_MOD(level, mod, format, ...) \ do { \ if (zlog_verify_level(level, mod)) { \ + if (zlog_vni_tag_get()) { \ + zlog_put_mdc("vni", zlog_vni_tag_get()); \ + } \ zlog_##level(zlog_get_mod_cat((mod)), format, ##__VA_ARGS__); \ } \ } while (0) @@ -71,12 +75,16 @@ typedef enum { #define LOG_MOD_HEX(level, mod, format, ...) \ do { \ if (zlog_verify_level(level, mod)) { \ + if (zlog_vni_tag_get()) { \ + zlog_put_mdc("vni", zlog_vni_tag_get()); \ + } \ hzlog_##level(zlog_get_mod_cat((mod)), format, ##__VA_ARGS__); \ } \ } while (0) zlog_category_t *zlog_get_mod_cat(ZLOG_MOD_NAME logMod); int zlog_verify_level(int level, ZLOG_MOD_NAME logMod); +const char *zlog_vni_tag_get(); #ifdef __cplusplus } #endif diff --git a/srcs/libs/init/init_runtime.c b/srcs/libs/init/init_runtime.c index 7eac072..a0f99f3 100644 --- a/srcs/libs/init/init_runtime.c +++ b/srcs/libs/init/init_runtime.c @@ -14,11 +14,13 @@ #include "inet_misc.h" #include "crypto.h" #include "hardware.h" -#include "msg_queue.h" #include "http_svr.h" #include "lib_config.h" #include "prj_config.h" #include "zlog_module.h" +#ifdef ZEROMQ_ON +#include "msg_queue.h" +#endif #define DEFAULT_CONFIG_FILE ("vcpe.cfg") #define DEFAULT_CONFIG_DIR ("config") @@ -40,6 +42,7 @@ int user_init(const char *pAppCfgFile, const char *pCfgDirectory, const char *pK UT_string *pPath; char bufCfgFile[MAX_PATH]; char bufCfgDir[MAX_PATH]; + char pidfile[MAX_PATH]; g_pid = uv_os_getpid(); @@ -112,6 +115,17 @@ int user_init(const char *pAppCfgFile, const char *pCfgDirectory, const char *pK LOG_MOD(info, ZLOG_MOD_INIT, "Application build configure: [%s]\n", VCPE_BUILD_CONFIG); +#ifdef USERVNI_ON + sprintf(pidfile, "/tmp/%d_vcpe.pid", cfg_get_user_vni_id()); +#else + sprintf(pidfile, "/tmp/vcpe.pid"); +#endif + + if (process_lock_pidfile(pidfile) == -ERR_FILE_LOCKED) { + LOG_MOD(error, ZLOG_MOD_INIT, "!!!Another same process is running!!!, system exit......\n"); + exit(-ERR_FILE_LOCKED); + } + if (cfg_get_banner_enable()) { banner_show(); } @@ -122,7 +136,7 @@ int user_init(const char *pAppCfgFile, const char *pCfgDirectory, const char *pK if (cfg_get_hardware_watch_enable()) { init_hardware(); } - +#ifdef ZEROMQ_ON if ((ret = mq_init()) != ERR_SUCCESS) { LOG_MOD(error, ZLOG_MOD_INIT, "Message queue init error: %d\n", ret); } @@ -130,6 +144,7 @@ int user_init(const char *pAppCfgFile, const char *pCfgDirectory, const char *pK if ((ret = mq_data_init()) != ERR_SUCCESS) { LOG_MOD(error, ZLOG_MOD_INIT, "Message queue init error: %d\n", ret); } +#endif #ifdef HTTPSERVER_ON http_svr_init(); #endif @@ -144,9 +159,12 @@ void user_uninit() { #ifdef HTTPSERVER_ON http_svr_uinit(); #endif +#ifdef ZEROMQ_ON mq_uninit(); +#endif zlog_fini(); uninit_config_system(); uv_loop_close(get_task_manager()); + process_unlock_pidfile(); } } diff --git a/srcs/libs/json/json_schema/CMakeLists.txt b/srcs/libs/json/json_schema/CMakeLists.txt new file mode 100644 index 0000000..cf6258f --- /dev/null +++ b/srcs/libs/json/json_schema/CMakeLists.txt @@ -0,0 +1,42 @@ +INCLUDE_DIRECTORIES(../../include/json_schema) + +SET(jsoncdac_SOURCES validate.c) + + +LIST(APPEND OPTIONAL + pattern patternproperties additionalproperties propertynames subschemalogic + contains store ref) + +FOREACH (src ${OPTIONAL}) + STRING(TOUPPER ${src} srcupper) + OPTION(BUILD_${srcupper} "${src} option" ON) + IF (BUILD_${srcupper}) + LIST(APPEND SUPPORTED_OPTIONAL ${src}) + SET(jsoncdac_SOURCES ${jsoncdac_SOURCES} ${src}.c) + ADD_DEFINITIONS(-DJDAC_${srcupper}) + ENDIF () +ENDFOREACH () + +IF (BUILD_PATTERNPROPERTIES OR BUILD_PATTERN) + SET(jsoncdac_SOURCES ${jsoncdac_SOURCES} regex_match.c) + #set(EXTRA_LIBS regex) +ENDIF () + +# always supported +LIST(APPEND SUPPORTED_BASE type enum required properties anyOf minLength maxLength minimum maximum const) +LIST(APPEND SUPPORTED_BASE minItems maxItems uniqueItems items) +STRING(REPLACE ";" "," SUPPORTED_BASE_STR "${SUPPORTED_BASE}") +STRING(REPLACE ";" "," SUPPORTED_OPTIONAL_STR "${SUPPORTED_OPTIONAL}") + +ADD_LIBRARY(jsoncdac STATIC ${jsoncdac_SOURCES}) +TARGET_COMPILE_DEFINITIONS(jsoncdac PRIVATE "SUPPORTED_KEYWORDS_BASE=\"${SUPPORTED_BASE_STR}\"" "SUPPORTED_KEYWORDS_OPTIONAL=\"${SUPPORTED_OPTIONAL_STR}\"") +TARGET_LINK_LIBRARIES(jsoncdac ${EXTRA_LIBS}) + +SET_TARGET_PROPERTIES( + jsoncdac + PROPERTIES + OUTPUT_NAME jsoncdac + PUBLIC_HEADER "${HEADER_FILES}" + VERSION 0.0.2 + SOVERSION 1 +) \ No newline at end of file diff --git a/srcs/libs/json/json_schema/additionalproperties.c b/srcs/libs/json/json_schema/additionalproperties.c new file mode 100644 index 0000000..b7db9eb --- /dev/null +++ b/srcs/libs/json/json_schema/additionalproperties.c @@ -0,0 +1,58 @@ +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +int _jdac_check_additionalproperties(json_object *jobj, json_object *jschema) { + json_object *jaddprops = json_object_object_get(jschema, "additionalProperties"); + + if (!jaddprops) { + return JDAC_ERR_VALID; + } + + if (!json_object_is_type(jaddprops, json_type_object) && !json_object_is_type(jaddprops, json_type_boolean)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + json_object *jprops = json_object_object_get(jschema, "properties"); +#ifdef JDAC_PATTERNPROPERTIES + json_object *jpatprops = json_object_object_get(jschema, "patternProperties"); +#endif + + json_object_object_foreach(jobj, jobj_key, jobj_val) { + + // if an instance key is found in properties, it is not an additional property + if (jprops) { + json_object *jprop = json_object_object_get(jprops, jobj_key); + if (jprop) { + continue; // ignore properties + } + } + + // if an instance key has a match in patternProperties, it is not an additional property +#ifdef JDAC_PATTERNPROPERTIES + int foundpatternproperty = 0; + if (jpatprops) { + if (json_object_is_type(jpatprops, json_type_object)) { + json_object_object_foreach(jpatprops, jpat_key, jpat_val) { + int ret = _jdac_match_string_with_regex(jpat_key, jobj_key); + if (ret == JDAC_REGEX_MATCH) { + foundpatternproperty = 1; + break; + } + } + } + if (foundpatternproperty) { + continue; + } + } +#endif + + // by this point we consider the instance to be an additional property + int err = _jdac_validate_instance(jobj_val, jaddprops); + if (err) { + return err; + } + } + + return JDAC_ERR_VALID; +} diff --git a/srcs/libs/json/json_schema/contains.c b/srcs/libs/json/json_schema/contains.c new file mode 100644 index 0000000..e943c29 --- /dev/null +++ b/srcs/libs/json/json_schema/contains.c @@ -0,0 +1,53 @@ +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +int _jdac_check_contains_and_minmaxcontains(json_object *jobj, json_object *jschema) { + int err; + + json_object *jcontains = json_object_object_get(jschema, "contains"); + if (!jcontains) { + return JDAC_ERR_VALID; + } + + if (!json_object_is_type(jcontains, json_type_object) && !json_object_is_type(jcontains, json_type_boolean)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + int arraylen = json_object_array_length(jobj); + + int match_count = 0; + for (int i = 0; i < arraylen; i++) { + json_object *iobj = json_object_array_get_idx(jobj, i); + err = _jdac_validate_instance(iobj, jcontains); + if (err == JDAC_ERR_VALID) { + match_count++; + } else if (err == JDAC_ERR_SCHEMA_ERROR) { + return JDAC_ERR_SCHEMA_ERROR; + } + } + + json_object *jmaxcontains = json_object_object_get(jschema, "maxContains"); + if (jmaxcontains) { + int max = json_object_get_int(jmaxcontains); + if (match_count > max) { + return JDAC_ERR_INVALID_CONTAINS; + } + } + + json_object *jmincontains = json_object_object_get(jschema, "minContains"); + if (jmincontains) { + int min = json_object_get_int(jmincontains); + if (min == 0) { + return JDAC_ERR_VALID; + } else if (match_count < min) { + return JDAC_ERR_INVALID_CONTAINS; + } + } + + if (match_count == 0) { + return JDAC_ERR_INVALID_CONTAINS; + } + + return JDAC_ERR_VALID; +} diff --git a/srcs/libs/json/json_schema/download.c b/srcs/libs/json/json_schema/download.c new file mode 100644 index 0000000..6a16ca9 --- /dev/null +++ b/srcs/libs/json/json_schema/download.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +struct curlmemory { + char *response; + size_t size; +}; + +static size_t cb(void *data, size_t size, size_t nmemb, void *userp) { + size_t realsize = size * nmemb; + struct curlmemory *mem = (struct curlmemory *)userp; + + char *ptr = realloc(mem->response, mem->size + realsize + 1); + if (ptr == NULL) { + return 0; /* out of memory! */ + } + + mem->response = ptr; + memcpy(&(mem->response[mem->size]), data, realsize); + mem->size += realsize; + mem->response[mem->size] = 0; + + return realsize; +} + +char *_jdac_download_schema(const char *url) { + struct curlmemory chunk = {0}; + + CURL *curl = curl_easy_init(); + if (curl) { + CURLcode res; + curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk); + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + curl_easy_cleanup(curl); + } + return chunk.response; +} + +const char *_jdac_download_resolve(const char *uri) { + int len = strlen(uri); + if (len > 8 && strncmp(uri, "http", 4) == 0) { + return uri; + } + return NULL; +} diff --git a/srcs/libs/json/json_schema/pattern.c b/srcs/libs/json/json_schema/pattern.c new file mode 100644 index 0000000..aee1d39 --- /dev/null +++ b/srcs/libs/json/json_schema/pattern.c @@ -0,0 +1,27 @@ +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +int _jdac_check_pattern(json_object *jobj, json_object *jschema) { + json_object *jpat = json_object_object_get(jschema, "pattern"); + if (jpat) { + if (!json_object_is_type(jpat, json_type_string)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + const char *pattern = json_object_get_string(jpat); + const char *istr = json_object_get_string(jobj); + + if (istr) { + int ret = _jdac_match_string_with_regex(pattern, istr); + if (ret == JDAC_REGEX_COMPILE_FAILED) { + return JDAC_ERR_SCHEMA_ERROR; + } else if (ret == JDAC_REGEX_MATCH) { + return JDAC_ERR_VALID; + } else if (ret == JDAC_REGEX_MISMATCH) { + return JDAC_ERR_INVALID_PATTERNMATCH; + } + } + } + return JDAC_ERR_VALID; +} diff --git a/srcs/libs/json/json_schema/patternproperties.c b/srcs/libs/json/json_schema/patternproperties.c new file mode 100644 index 0000000..bc18123 --- /dev/null +++ b/srcs/libs/json/json_schema/patternproperties.c @@ -0,0 +1,32 @@ +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +int _jdac_check_patternproperties(json_object *jobj, json_object *jschema) { + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", __func__); + // check jobj non object is already checked + + json_object *jpatprops = json_object_object_get(jschema, "patternProperties"); + if (jpatprops) { + if (!json_object_is_type(jpatprops, json_type_object)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + json_object_object_foreach(jpatprops, jprop_key, jprop_val) { + json_object_object_foreach(jobj, jobj_key, jobj_val) { + int ret = _jdac_match_string_with_regex(jprop_key, jobj_key); + if (ret == JDAC_REGEX_COMPILE_FAILED) { + return JDAC_ERR_SCHEMA_ERROR; + } else if (ret == JDAC_REGEX_MATCH) { + int err = _jdac_validate_instance(jobj_val, jprop_val); + if (err) { + return err; + } + } else if (ret == JDAC_REGEX_MISMATCH) { + // + } + } + } + } + return JDAC_ERR_VALID; +} diff --git a/srcs/libs/json/json_schema/propertynames.c b/srcs/libs/json/json_schema/propertynames.c new file mode 100644 index 0000000..13e1182 --- /dev/null +++ b/srcs/libs/json/json_schema/propertynames.c @@ -0,0 +1,26 @@ +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +int _jdac_check_propertynames(json_object *jobj, json_object *jschema) { + json_object *jpropnames_schema = json_object_object_get(jschema, "propertyNames"); + if (!jpropnames_schema) { + return JDAC_ERR_VALID; + } + + if (!json_object_is_type(jpropnames_schema, json_type_object) && + !json_object_is_type(jpropnames_schema, json_type_boolean)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + json_object_object_foreach(jobj, jprop_key, jprop_val) { + json_object *jprop = json_object_new_string(jprop_key); + int err = _jdac_validate_instance(jprop, jpropnames_schema); + json_object_put(jprop); + if (err) { + return err; + } + } + + return JDAC_ERR_VALID; +} diff --git a/srcs/libs/json/json_schema/ref.c b/srcs/libs/json/json_schema/ref.c new file mode 100644 index 0000000..a1b876a --- /dev/null +++ b/srcs/libs/json/json_schema/ref.c @@ -0,0 +1,89 @@ +#include +#include +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" +#include "../../include/zlog_module.h" + +char localpath[256] = {0}; + +int jdac_ref_set_localpath(const char *_localpath) { + strcpy(localpath, _localpath); + return JDAC_ERR_VALID; +} + +const char *_jdac_uri_get_path(const char *uri) { + const char *ptr = uri; + char *schemaseparator = strstr(uri, "://"); + if (!schemaseparator) { + //no schema + + } else { + //has schema + ptr = schemaseparator + 3; + char *path = strstr(ptr, "/"); + if (path) { + return path; + } + } + return NULL; +} + +int _jdac_check_ref(json_object *jobj, json_object *jschema, storage_node *storage_list) { + // #ifdef JDAC_STORE + json_object *jref = json_object_object_get(jschema, "$ref"); + if (jref) { + const char *refstr = json_object_get_string(jref); + LOG_MOD(trace, ZLOG_MOD_JSCHEM, "ref is %s\n", refstr); + storage_node *rootnode = _jdac_store_get_root_node(storage_list); + // if there is a rootnode id, compare it to the ref + if (rootnode) { + const char *path_ref = _jdac_uri_get_path(refstr); + const char *path_id = _jdac_uri_get_path(rootnode->id); + + if (!path_ref) { + return JDAC_ERR_VALID; + } + + if (!path_id) { + char filepath[512]; + snprintf(filepath, sizeof(filepath) - 1, "%s.%s", localpath, path_ref); + LOG_MOD(trace, ZLOG_MOD_JSCHEM, "filepath is %s\n", filepath); + json_object *jschemafromfile = json_object_from_file(filepath); + if (!jschemafromfile) { + return JDAC_ERR_JSON_NOT_FOUND; + } + int err = _jdac_validate_instance(jobj, jschemafromfile); + json_object_put(jschemafromfile); + return err; + } + + if (strcmp(path_ref, path_id) != 0 && strlen(localpath) > 0) { + LOG_MOD(trace, ZLOG_MOD_JSCHEM, "yep\n"); + char filepath[512]; + snprintf(filepath, sizeof(filepath) - 1, "%s.%s", localpath, path_ref); + LOG_MOD(trace, ZLOG_MOD_JSCHEM, "filepath is %s\n", filepath); + json_object *jschemafromfile = json_object_from_file(filepath); + if (!jschemafromfile) { + return JDAC_ERR_JSON_NOT_FOUND; + } + int err = _jdac_validate_instance(jobj, jschemafromfile); + json_object_put(jschemafromfile); + return err; + } else if (strcmp(path_ref, path_id) == 0) { + int err = _jdac_validate_instance(jobj, rootnode->json_schema_ptr); + return err; + } + } + + // if (refstr) { + // json_object *jschema_from_resolved_uri = _jdac_store_resolve(storage_list, refstr); + // if (!jschema_from_resolved_uri) + // return JDAC_ERR_INVALID_REF; + // int err = _jdac_validate_instance(jobj, jschema_from_resolved_uri); + // return err; + // } + } + // #endif + return JDAC_ERR_VALID; +} \ No newline at end of file diff --git a/srcs/libs/json/json_schema/regex_match.c b/srcs/libs/json/json_schema/regex_match.c new file mode 100644 index 0000000..a8967ee --- /dev/null +++ b/srcs/libs/json/json_schema/regex_match.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include "jsoncdaccord.h" +#include "../../include/zlog_module.h" + +int _jdac_match_string_with_regex(const char *regex_pattern, const char *value) { + regex_t regex; + int reti = regcomp(®ex, regex_pattern, REG_EXTENDED); + if (reti) { + LOG_MOD(error, ZLOG_MOD_JSCHEM, "Could not compile regex\n"); + return JDAC_REGEX_COMPILE_FAILED; + } + reti = regexec(®ex, value, 0, NULL, 0); + regfree(®ex); + if (reti == 0) { + return JDAC_REGEX_MATCH; + } + return JDAC_REGEX_MISMATCH; +} diff --git a/srcs/libs/json/json_schema/store.c b/srcs/libs/json/json_schema/store.c new file mode 100644 index 0000000..7ee88d9 --- /dev/null +++ b/srcs/libs/json/json_schema/store.c @@ -0,0 +1,135 @@ +#include +#include +#include "jsoncdaccord.h" +#include "optional.h" +#include "../../include/zlog_module.h" + +void _jdac_store_append(storage_node **head, storage_node *ref) { + storage_node *new_node = malloc(sizeof(storage_node)); + memcpy(new_node, ref, sizeof(storage_node)); + new_node->next = *head; + *head = new_node; +} + +void _jdac_store_free(storage_node **head) { + while (*head) { + // if ((*head)->is_root==1 && (*head)->json_instance_ptr!=NULL) + // json_object_put((*head)->json_instance_ptr); + storage_node *el = *head; + *head = (*head)->next; + free(el); + } + *head = NULL; +} + +int _jdac_store_traverse_json(storage_node **head, json_object *jschema, char *pathbuffer) { + char pathbuf[256]; + pathbuf[0] = 0; + storage_node node = {0}; + + if (pathbuffer == NULL) { + strcpy(pathbuf, "#/"); + node.is_root = 1; + } else { + strcpy(pathbuf, pathbuffer); + node.is_root = 0; + } + node.json_instance_ptr = jschema; + + json_object *jid = json_object_object_get(jschema, "$id"); + json_object *janchor = json_object_object_get(jschema, "$anchor"); + json_object *jdynamicanchor = json_object_object_get(jschema, "$dynamicAnchor"); + + if (jid) { + strcpy(node.id, json_object_get_string(jid)); + } + + if (janchor) { + strcpy(node.anchor, json_object_get_string(janchor)); + } + + if (jdynamicanchor) { + strcpy(node.dynamicAnchor, json_object_get_string(jdynamicanchor)); + } + + // if (jid || janchor || jdynamicanchor || node.is_root==1) { + strcpy(node.JSONPtrURI, pathbuf); + node.json_schema_ptr = jschema; + _jdac_store_append(head, &node); + // } + + json_object_object_foreach(jschema, jkey, jval) { + if (json_object_is_type(jval, json_type_object)) { + + if (strcmp(jkey, "const") == 0) { + continue; + } + + if (pathbuffer == NULL) { + sprintf(pathbuf, "#/%s", jkey); + } else { + sprintf(pathbuf, "%s/%s", pathbuffer, jkey); + } + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", pathbuf); + _jdac_store_traverse_json(head, jval, pathbuf); + } + } + return JDAC_ERR_VALID; +} + +void _jdac_store_print(storage_node *head) { + storage_node *list = head; + LOG_MOD(trace, + ZLOG_MOD_JSCHEM, + "%-*s %-*s %-*s %-*s\n", + 32, + "JSONPtr", + 16, + "anchor", + 16, + "dynamicAnchor", + 32, + "id"); + while (list) { + LOG_MOD(trace, + ZLOG_MOD_JSCHEM, + "%-*s %-*s %-*s %-*s\n", + 32, + list->JSONPtrURI, + 16, + list->anchor, + 16, + list->dynamicAnchor, + 32, + list->id); + list = list->next; + } +} + +storage_node *_jdac_store_get_root_node(storage_node *head) { + // spool to start of list + storage_node *list = head; + //LOG_MOD(trace, ZLOG_MOD_JSCHEM, "%-*s %-*s %-*s %-*s\n", 32, "JSONPtr", 16, "anchor", 16, "dynamicAnchor", 32, "id"); + while (list) { + //LOG_MOD(trace, ZLOG_MOD_JSCHEM, "%-*s %-*s %-*s %-*s\n", 32, list->JSONPtrURI, 16, list->anchor, 16, list->dynamicAnchor, 32, list->id); + if (list->next == NULL) { + return list; + } + list = list->next; + } + return NULL; +} + +json_object *_jdac_store_resolve(storage_node *list, const char *uri) { + while (list) { + if (strcmp(list->id, uri) == 0) { + return list->json_instance_ptr; + } + if (strcmp(list->JSONPtrURI, uri) == 0) { + return list->json_instance_ptr; + } + list = list->next; + } + + return NULL; +} \ No newline at end of file diff --git a/srcs/libs/json/json_schema/subschemalogic.c b/srcs/libs/json/json_schema/subschemalogic.c new file mode 100644 index 0000000..d0dbc67 --- /dev/null +++ b/srcs/libs/json/json_schema/subschemalogic.c @@ -0,0 +1,116 @@ +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" + +enum subschematype { + JDAC_ALLOF = 0, + JDAC_ANYOF, + JDAC_ONEOF +}; + +// shall return valid or invalid based on subschema type +int _jdac_test_subschema_array(json_object *jobj, json_object *jsubschema_array, enum subschematype type) { + if (jsubschema_array == NULL) { + return JDAC_ERR_VALID; + } + + // MUST be a non-empty array + if (!json_object_is_type(jsubschema_array, json_type_array)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + int arraylen = (int)json_object_array_length(jsubschema_array); + if (arraylen == 0) { + return JDAC_ERR_SCHEMA_ERROR; + } + + int number_of_valid_schemas = 0; + + for (int i = 0; i < arraylen; i++) { + json_object *jsubschema = json_object_array_get_idx(jsubschema_array, i); + if (!json_object_is_type(jsubschema, json_type_object) && !json_object_is_type(jsubschema, json_type_boolean)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + int err = _jdac_validate_instance(jobj, jsubschema); + + if (err == JDAC_ERR_VALID) { + number_of_valid_schemas++; + } else if (err == JDAC_ERR_SCHEMA_ERROR) { + return JDAC_ERR_SCHEMA_ERROR; + } else { + // continue + } + } + + if (type == JDAC_ALLOF) { + if (number_of_valid_schemas == arraylen) { + return JDAC_ERR_VALID; + } + } else if (type == JDAC_ANYOF) { + if (number_of_valid_schemas > 0) { + return JDAC_ERR_VALID; + } + } else if (type == JDAC_ONEOF) { + if (number_of_valid_schemas == 1) { + return JDAC_ERR_VALID; + } + } + return JDAC_ERR_INVALID_SUBSCHEMALOGIC; +} + +int _jdac_check_subschemalogic(json_object *jobj, json_object *jschema) { + int err; + json_object *jarray; + + jarray = json_object_object_get(jschema, "allOf"); + err = _jdac_test_subschema_array(jobj, jarray, JDAC_ALLOF); + if (err) { + return JDAC_ERR_INVALID_SUBSCHEMALOGIC; + } + + jarray = json_object_object_get(jschema, "anyOf"); + err = _jdac_test_subschema_array(jobj, jarray, JDAC_ANYOF); + if (err) { + return JDAC_ERR_INVALID_SUBSCHEMALOGIC; + } + + jarray = json_object_object_get(jschema, "oneOf"); + err = _jdac_test_subschema_array(jobj, jarray, JDAC_ONEOF); + if (err) { + return JDAC_ERR_INVALID_SUBSCHEMALOGIC; + } + + json_object *jnot = json_object_object_get(jschema, "not"); + if (jnot) { + // "not" is special, and MUST be a json object + if (json_object_is_type(jnot, json_type_object) || json_object_is_type(jnot, json_type_boolean)) { + err = _jdac_validate_instance(jobj, jnot); + if (err == JDAC_ERR_VALID) { + return JDAC_ERR_INVALID_SUBSCHEMALOGIC; + } else if (err == JDAC_ERR_SCHEMA_ERROR) { + return JDAC_ERR_SCHEMA_ERROR; + } else { + return JDAC_ERR_VALID; + } + } else { + return JDAC_ERR_SCHEMA_ERROR; + } + } + + json_object *if_schema = json_object_object_get(jschema, "if"); + json_object *then_schema = json_object_object_get(jschema, "then"); + json_object *else_schema = json_object_object_get(jschema, "else"); + if (if_schema) { + err = _jdac_validate_instance(jobj, if_schema); + if (err == JDAC_ERR_VALID && then_schema) { + err = _jdac_validate_instance(jobj, then_schema); + return err; + } else if (err != JDAC_ERR_VALID && else_schema) { + err = _jdac_validate_instance(jobj, else_schema); + return err; + } + } + + return JDAC_ERR_VALID; +} diff --git a/srcs/libs/json/json_schema/validate.c b/srcs/libs/json/json_schema/validate.c new file mode 100644 index 0000000..5cecff4 --- /dev/null +++ b/srcs/libs/json/json_schema/validate.c @@ -0,0 +1,649 @@ +#include +#include +#include +#include + +#include "jsoncdaccord.h" +#include "internal.h" +#include "optional.h" +#include "../../include/zlog_module.h" + +json_object *json = NULL; +json_object *schema = NULL; +json_object *defs = NULL; + +#ifdef JDAC_STORE +static storage_node *storagelist_head = NULL; +#endif + +static char *jdacerrstr[JDAC_ERR_MAX] = {"VALID", + "GENERAL ERROR", + "JSON FILE NOT FOUND", + "SCHEMA FILE NOT FOUND", + "WRONG ARGUEMNTS GIVEN", + "SCHEMA ERROR", + "INVALID", + "INVALID TYPE", + "INVALID REQUIRED", + "INVALID SUBSCHEMA LOGIC (allOf, anyOf, oneOf, or not)", + "INVALID CONST", + "INVALID ENUMS", + "INVALID STRING LENGTH", + "INVALID UNIQUE ITEMS", + "INVALID UNIQUE CONTAINS", + "INVALID PREFIXITEMS", + "INVALID ITEMS", + "INVALID ARRAY LENGTH", + "INVALID NUMBER", + "INVALID REFERENCE", + "PATTERN NO MATCH", + "REGEX MISMATCH", + "REGEX MATCH", + "REGEX COMPILE FAILED"}; + +const char *jdac_errorstr(unsigned int jdac_errors) { + if (jdac_errors < JDAC_ERR_MAX) { + return jdacerrstr[jdac_errors]; + } + return NULL; +} + +int _jdac_load(const char *jsonfile, const char *jsonschema) { + json = json_object_from_file(jsonfile); + if (json == NULL) { + return JDAC_ERR_JSON_NOT_FOUND; + } + + schema = json_object_from_file(jsonschema); + if (schema == NULL) { + json_object_put(json); + return JDAC_ERR_SCHEMA_NOT_FOUND; + } + + return JDAC_ERR_VALID; +} + +int __jdac_inspect_type(json_object *jobj, const char *type) { + if (strcmp(type, "object") == 0) { + if (json_object_is_type(jobj, json_type_object)) { + return JDAC_ERR_VALID; + } + } else if (strcmp(type, "array") == 0) { + if (json_object_is_type(jobj, json_type_array)) { + return JDAC_ERR_VALID; + } + } else if (strcmp(type, "string") == 0) { + if (json_object_is_type(jobj, json_type_string)) { + return JDAC_ERR_VALID; + } + } else if (strcmp(type, "integer") == 0) { + if (json_object_is_type(jobj, json_type_int)) { + return JDAC_ERR_VALID; + } + if (json_object_is_type(jobj, json_type_double)) { + double value = json_object_get_double(jobj); + if (value == round(value)) { // "zero fractional part is an integer" + return JDAC_ERR_VALID; + } + } + } else if (strcmp(type, "double") == 0) { + if (json_object_is_type(jobj, json_type_double)) { + return JDAC_ERR_VALID; + } + } else if (strcmp(type, "number") == 0) { + if (json_object_is_type(jobj, json_type_double) || json_object_is_type(jobj, json_type_int)) { + return JDAC_ERR_VALID; + } + } else if (strcmp(type, "boolean") == 0) { + if (json_object_is_type(jobj, json_type_boolean)) { + return JDAC_ERR_VALID; + } + } else if (strcmp(type, "null") == 0) { + if (json_object_is_type(jobj, json_type_null)) { + return JDAC_ERR_VALID; + } + } else { + LOG_MOD(warn, ZLOG_MOD_JSCHEM, "WARN unknown type in check type %s\n", type); + return JDAC_ERR_SCHEMA_ERROR; + } + return JDAC_ERR_INVALID_TYPE; +} + +int _jdac_check_type(json_object *jobj, json_object *jschema) { + json_object *jtype = json_object_object_get(jschema, "type"); + + if (jtype == NULL) { + return JDAC_ERR_VALID; + } else if (json_object_is_type(jtype, json_type_string)) { + const char *type = json_object_get_string(jtype); + return __jdac_inspect_type(jobj, type); + } else if (json_object_is_type(jtype, json_type_array)) { + int arraylen = json_object_array_length(jtype); + for (int i = 0; i < arraylen; i++) { + json_object *iobj = json_object_array_get_idx(jtype, i); + if (!json_object_is_type(iobj, json_type_string)) { + return JDAC_ERR_SCHEMA_ERROR; + } + const char *type = json_object_get_string(iobj); + int err = __jdac_inspect_type(jobj, type); + if (err == JDAC_ERR_VALID) { + return JDAC_ERR_VALID; + } + } + return JDAC_ERR_INVALID_TYPE; + } else { + return JDAC_ERR_SCHEMA_ERROR; + } +} + +int _jdac_check_required(json_object *jobj, json_object *jschema) { + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n%s\n", __func__, json_object_to_json_string(jobj)); + json_object *jarray = json_object_object_get(jschema, "required"); + int missing_required_key = 0; + if (jarray) { + int arraylen = json_object_array_length(jarray); + for (int i = 0; i < arraylen; i++) { + json_object *iobj = json_object_array_get_idx(jarray, i); + const char *key = json_object_get_string(iobj); + if (key) { + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", key); + // use json_object_object_get_ex becuase of json_type_null types + json_object *required_object = NULL; + int err = json_object_object_get_ex(jobj, key, &required_object); + if (err == 0) { + LOG_MOD(debug, ZLOG_MOD_JSCHEM, "required key missing: %s\n", key); + missing_required_key = 1; + } + } + } + } + if (missing_required_key) { + return JDAC_ERR_INVALID_REQUIRED; + } else { + return JDAC_ERR_VALID; + } +} + +int _jdac_check_properties(json_object *jobj, json_object *jschema) { + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", __func__); + + json_object *jprops = json_object_object_get(jschema, "properties"); + if (jprops) { + json_object_object_foreach(jprops, jprop_key, jprop_val) { + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "key of prop is %s\n", jprop_key); + json_object *iobj = json_object_object_get(jobj, jprop_key); + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "iobj %s type %d\nkey %s\nval %s\n", json_object_get_string(iobj), json_object_get_type(iobj), jprop_key, json_object_get_string(jprop_val)); + if (iobj) { + int err = _jdac_validate_instance(iobj, jprop_val); + if (err) { + return err; + } + } + } + } + return JDAC_ERR_VALID; +} + +int _jdac_check_prefixItems_and_items(json_object *jobj, json_object *jschema) { + json_object *jprefixitems = json_object_object_get(jschema, "prefixItems"); + json_object *jitems = json_object_object_get(jschema, "items"); + + int jobj_arraylen = json_object_array_length(jobj); + int prefixitems_arraylen = 0; + + if (jprefixitems) { + + if (!json_object_is_type(jprefixitems, json_type_array)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + prefixitems_arraylen = json_object_array_length(jprefixitems); + + for (int i = 0; i < jobj_arraylen && i < prefixitems_arraylen; i++) { + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "i=%d prefixitems\n", i); + json_object *iobj = json_object_array_get_idx(jobj, i); + json_object *ischema = json_object_array_get_idx(jprefixitems, i); + int err = _jdac_validate_instance(iobj, ischema); + if (err) { + return JDAC_ERR_INVALID_PREFIXITEMS; + } + } + } + + if (jitems) { + if (!json_object_is_type(jitems, json_type_object) && !json_object_is_type(jitems, json_type_boolean)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + for (int i = prefixitems_arraylen; i < jobj_arraylen; i++) { + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "i=%d items\n", i); + json_object *iobj = json_object_array_get_idx(jobj, i); + int err = _jdac_validate_instance(iobj, jitems); + if (err) { + return JDAC_ERR_INVALID_ITEMS; + } + } + } + return JDAC_ERR_VALID; +} + +json_object *_jdac_get_defs_from_ref(json_object *ref) { + char key[128]; + if (!json_object_is_type(ref, json_type_string)) { + return NULL; + } + + const char *refstr = json_object_get_string(ref); + if (sscanf(refstr, "#/$defs/%s", key) == 1) { + return json_object_object_get(defs, key); + } + return NULL; +} + +int _jdac_value_is_equal(json_object *jobj1, json_object *jobj2) { + if (json_object_equal(jobj1, jobj2)) { + return JDAC_ERR_VALID; + } + + if (json_object_is_type(jobj1, json_type_double) && json_object_is_type(jobj2, json_type_int)) { + double value = json_object_get_double(jobj1); + double value2 = json_object_get_int64(jobj2); + if (value == round(value) && value == value2) { + return JDAC_ERR_VALID; + } + } + + if (json_object_is_type(jobj1, json_type_int) && json_object_is_type(jobj2, json_type_double)) { + double value = json_object_get_double(jobj2); + double value2 = json_object_get_int64(jobj1); + if (value == round(value) && value == value2) { + return JDAC_ERR_VALID; + } + } + + return JDAC_ERR_INVALID; +} + +int _jdac_check_const(json_object *jobj, json_object *jschema) { + json_object *jconst; + int err = json_object_object_get_ex(jschema, "const", &jconst); + if (err == 0) { + return JDAC_ERR_VALID; + } + + err = _jdac_value_is_equal(jobj, jconst); + if (err == JDAC_ERR_VALID) { + return JDAC_ERR_VALID; + } + + return JDAC_ERR_INVALID_CONST; +} + +int _jdac_check_enums(json_object *jobj, json_object *jschema) { + json_object *jenum_array = json_object_object_get(jschema, "enum"); + + if (!jenum_array) { + return JDAC_ERR_VALID; + } + + if (!json_object_is_type(jenum_array, json_type_array)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + int arraylen = json_object_array_length(jenum_array); + for (int i = 0; i < arraylen; i++) { + json_object *ienum = json_object_array_get_idx(jenum_array, i); + + int err = _jdac_value_is_equal(jobj, ienum); + if (err == JDAC_ERR_VALID) { + return JDAC_ERR_VALID; + } + } + LOG_MOD(error, ZLOG_MOD_JSCHEM, "ERROR: enum check failed (%s not in enum)\n", json_object_to_json_string(jobj)); + + return JDAC_ERR_INVALID_ENUMS; +} + +int _jdac_check_uniqueItems(json_object *jobj, json_object *jschema) { + json_object *juniq = json_object_object_get(jschema, "uniqueItems"); + if (juniq) { + if (!json_object_is_type(juniq, json_type_boolean)) { + return JDAC_ERR_SCHEMA_ERROR; + } + + if (json_object_get_boolean(juniq) == 0) { + return JDAC_ERR_VALID; + } + + int arraylen = json_object_array_length(jobj); + for (int i = 0; i < arraylen - 1; i++) { + json_object *iobj = json_object_array_get_idx(jobj, i); + for (int j = i + 1; j < arraylen; j++) { + json_object *uobj = json_object_array_get_idx(jobj, j); + if (json_object_equal(iobj, uobj) == 1) { + return JDAC_ERR_INVALID_UNIQUEITEMS; + } + } + } + } + return JDAC_ERR_VALID; +} + +int _jdac_check_maxmin_items(json_object *jobj, json_object *jschema) { + int err = JDAC_ERR_VALID; + json_object *jmax = json_object_object_get(jschema, "maxItems"); + json_object *jmin = json_object_object_get(jschema, "minItems"); + int arraylen = json_object_array_length(jobj); + + if (jmax) { + if (json_object_is_type(jmax, json_type_int) || json_object_is_type(jmax, json_type_double)) { + int maxitems = json_object_get_double(jmax); + if (arraylen > maxitems) { + err = JDAC_ERR_INVALID_ARRAYLEN; + } + } + } + + if (jmin) { + if (json_object_is_type(jmin, json_type_int) || json_object_is_type(jmin, json_type_double)) { + int minitems = json_object_get_double(jmin); + if (arraylen < minitems) { + err = JDAC_ERR_INVALID_ARRAYLEN; + } + } + } + + if (err) { + LOG_MOD(error, ZLOG_MOD_JSCHEM, "ERROR: failed at maxItems or minItems check\n"); + } + return err; +} + +int _jdac_validate_array(json_object *jobj, json_object *jschema) { + int err; + + err = _jdac_check_prefixItems_and_items(jobj, jschema); + if (err) { + return err; + } + + err = _jdac_check_uniqueItems(jobj, jschema); + if (err) { + return err; + } + + err = _jdac_check_maxmin_items(jobj, jschema); + if (err) { + return err; + } + +#ifdef JDAC_CONTAINS + err = _jdac_check_contains_and_minmaxcontains(jobj, jschema); + if (err) { + return err; + } +#endif + + return JDAC_ERR_VALID; +} + +int _jdac_validate_object(json_object *jobj, json_object *jschema) { + int err; + if (defs == NULL) { + defs = json_object_object_get(jschema, "$defs"); + } + + err = _jdac_check_required(jobj, jschema); + if (err) { + return err; + } + + err = _jdac_check_properties(jobj, jschema); + if (err) { + return err; + } + +#ifdef JDAC_PROPERTYNAMES + err = _jdac_check_propertynames(jobj, jschema); + if (err) { + return err; + } +#endif + +#ifdef JDAC_PATTERNPROPERTIES + err = _jdac_check_patternproperties(jobj, jschema); + if (err) { + return err; + } +#endif + +#ifdef JDAC_ADDITIONALPROPERTIES + err = _jdac_check_additionalproperties(jobj, jschema); + if (err) { + return err; + } +#endif + + return JDAC_ERR_VALID; +} + +int utf8_length(const char *str) { + const char *pointer = str; + int len = 0; + while (pointer[0]) { + if ((pointer[0] & 0xC0) != 0x80) { + len++; + } + pointer++; + } + return len; +} + +int _jdac_validate_string(json_object *jobj, json_object *jschema) { + const char *str = json_object_get_string(jobj); + //LOG_MOD(debug, ZLOG_MOD_JSCHEM, "strlen of %s %ld %d %d\n", str, strlen(str), json_object_get_string_len(jobj), utf8_length(str)); + json_object *jminlen = json_object_object_get(jschema, "minLength"); + if (jminlen) { + int minlen = json_object_get_int64(jminlen); + if (utf8_length(str) < minlen) { + return JDAC_ERR_INVALID_STRLEN; + } + } + json_object *jmaxlen = json_object_object_get(jschema, "maxLength"); + if (jmaxlen) { + int maxlen = json_object_get_int64(jmaxlen); + if (utf8_length(str) > maxlen) { + return JDAC_ERR_INVALID_STRLEN; + } + } + + int err = _jdac_check_enums(jobj, jschema); + if (err) { + return err; + } + +#ifdef JDAC_PATTERN + err = _jdac_check_pattern(jobj, jschema); + if (err) { + return err; + } +#endif + + return JDAC_ERR_VALID; +} + +int _jdac_validate_integer(json_object *jobj, json_object *jschema) { + double value = (double)json_object_get_int64(jobj); + int err = _jdac_validate_number(jobj, jschema, value); + return err; +} + +int _jdac_validate_double(json_object *jobj, json_object *jschema) { + double value = json_object_get_double(jobj); + int err = _jdac_validate_number(jobj, jschema, value); + return err; +} + +int _jdac_validate_number(json_object *jobj, json_object *jschema, double value) { + + json_object *jmult = json_object_object_get(jschema, "multipleOf"); + if (jmult) { + double multipland = (double)json_object_get_double(jmult); + if (multipland == 0.0) { + return JDAC_ERR_SCHEMA_ERROR; + } + double divided = value / multipland; + if (isinf(divided) != 0) { + return JDAC_ERR_INVALID_NUMBER; + } + if (divided != round(divided)) { + return JDAC_ERR_INVALID_NUMBER; + } + } + + json_object *jmin = json_object_object_get(jschema, "minimum"); + if (jmin) { + double min = (double)json_object_get_double(jmin); + if (value < min) { + return JDAC_ERR_INVALID_NUMBER; + } + } + + json_object *jexclmin = json_object_object_get(jschema, "exclusiveMinimum"); + if (jexclmin) { + double min = (double)json_object_get_double(jexclmin); + if (value <= min) { + return JDAC_ERR_INVALID_NUMBER; + } + } + + json_object *jmax = json_object_object_get(jschema, "maximum"); + if (jmax) { + double max = (double)json_object_get_double(jmax); + if (value > max) { + return JDAC_ERR_INVALID_NUMBER; + } + } + + json_object *jexclmax = json_object_object_get(jschema, "exclusiveMaximum"); + if (jexclmax) { + double max = (double)json_object_get_double(jexclmax); + if (value >= max) { + return JDAC_ERR_INVALID_NUMBER; + } + } + + return JDAC_ERR_VALID; +} + +int _jdac_validate_boolean(json_object *jobj, json_object *jschema) { + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", __func__); + return JDAC_ERR_VALID; +} + +int _jdac_validate_instance(json_object *jobj, json_object *jschema) { + int err; + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "--validate instance--\n"); + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", json_object_get_string(jobj)); + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", json_object_get_string(jschema)); + +#ifdef JDAC_REF + err = _jdac_check_ref(jobj, jschema, storagelist_head); + if (err) { + return err; + } +#endif + + // check if jschema is a bool, true or false + if (json_object_is_type(jschema, json_type_boolean)) { + json_bool value = json_object_get_boolean(jschema); + if (value == 0) { + return JDAC_ERR_INVALID; + } + if (value == 1) { + return JDAC_ERR_VALID; + } + } + + err = _jdac_check_type(jobj, jschema); + if (err) { + return err; + } + + err = _jdac_check_const(jobj, jschema); + if (err) { + return err; + } + + err = _jdac_check_enums(jobj, jschema); + if (err) { + return err; + } + + // if (!json_object_is_type(jobj, json_type_null)) + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", json_object_get_string(jobj)); + // else + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "jobj was null\n"); + // if (!json_object_is_type(jschema, json_type_null)) + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "%s\n", json_object_get_string(jschema)); + // else + // LOG_MOD(debug, ZLOG_MOD_JSCHEM, "jschema was null\n"); + +#ifdef JDAC_SUBSCHEMALOGIC + err = _jdac_check_subschemalogic(jobj, jschema); + if (err) { + return err; + } +#endif + + json_type type = json_object_get_type(jobj); + + if (type == json_type_object) { + return _jdac_validate_object(jobj, jschema); + } else if (type == json_type_array) { + return _jdac_validate_array(jobj, jschema); + } else if (type == json_type_string) { + return _jdac_validate_string(jobj, jschema); + } else if (type == json_type_boolean) { + return _jdac_validate_boolean(jobj, jschema); + } else if (type == json_type_int) { + return _jdac_validate_integer(jobj, jschema); + } else if (type == json_type_double) { + return _jdac_validate_double(jobj, jschema); + } else if (type == json_type_null) { + return JDAC_ERR_VALID; + } else { + LOG_MOD(warn, ZLOG_MOD_JSCHEM, "WARN: type %d not handled\n", type); + } + + return JDAC_ERR_VALID; +} + +int jdac_validate(json_object *jobj, json_object *jschema) { +#ifdef JDAC_STORE + _jdac_store_traverse_json(&storagelist_head, jschema, NULL); + _jdac_store_print(storagelist_head); +#endif + + int err = _jdac_validate_instance(jobj, jschema); +#ifdef JDAC_STORE + _jdac_store_free(&storagelist_head); +#endif + return err; +} + +int jdac_validate_file(const char *jsonfile, const char *jsonschemafile) { + int err = _jdac_load(jsonfile, jsonschemafile); + if (err) { + return err; + } + + err = jdac_validate(json, schema); + + json_object_put(json); + json_object_put(schema); + json = NULL; + schema = NULL; + defs = NULL; + return err; +} diff --git a/srcs/libs/misc/unique_instance.c b/srcs/libs/misc/unique_instance.c new file mode 100644 index 0000000..cbaa38e --- /dev/null +++ b/srcs/libs/misc/unique_instance.c @@ -0,0 +1,33 @@ +// +// Created by xajhuang on 2023/3/2. +// +#include +#include +#include +#include +#include +#include "user_errno.h" +#include "misc.h" +static int g_lockfd = -1; +static char g_pidPath[MAX_PATH] = {0}; + +int process_lock_pidfile(char *pFilePath) { + if (pFilePath == NULL || strlen(pFilePath) == 0) { + return ERR_SUCCESS; + } + + strcpy(g_pidPath, pFilePath); + + g_lockfd = open(pFilePath, O_CREAT | O_RDWR, 0666); // open file + int rc = flock(g_lockfd, LOCK_EX | LOCK_NB); // lock access to open file + if (rc && EWOULDBLOCK == errno) { // check lock success + return -ERR_FILE_LOCKED; // another instance is running + } + + return ERR_SUCCESS; +} + +void process_unlock_pidfile() { + close(g_lockfd); + unlink(g_pidPath); +} \ No newline at end of file diff --git a/srcs/libs/cmdline/mq_cmd.c b/srcs/libs/mq/mq_cmd.c similarity index 100% rename from srcs/libs/cmdline/mq_cmd.c rename to srcs/libs/mq/mq_cmd.c diff --git a/srcs/libs/protocol/protocol.c b/srcs/libs/protocol/protocol.c index f8a78c0..3c7c92f 100644 --- a/srcs/libs/protocol/protocol.c +++ b/srcs/libs/protocol/protocol.c @@ -10,7 +10,9 @@ #include "crypto.h" #include "user_errno.h" #include "zlog_module.h" - +#ifdef JSON_SCHEMA_ON +#include "json_schema/jsoncdaccord.h" +#endif #define CURRENT_PROTOCOL_VERSION (1) typedef struct { @@ -21,14 +23,121 @@ typedef struct { cJSON *msgContend; } PROTOCOL_WARP, *PPROTOCOL_WARP; -const char *proto_decode_context(const char *pString, unsigned int *pVer, unsigned long long *pTm) { +#ifdef JSON_SCHEMA_ON +typedef struct { + const char *pSchJson; + const char *pErrMsg; +} JSON_SCHEMA_CTX, *PJSON_SCHEMA_CTX; + +static JSON_SCHEMA_CTX g_json_sch[] = { + {"{\"type\":\"object\",\"required\":[\"ver\"]}", "Missing required field [ver]" }, + {"{\"type\":\"object\",\"required\":[\"cryptoType\"]}", "Missing required field [cryptoType]" }, + {"{\"type\":\"object\",\"required\":[\"timeStamp\"]}", "Missing required field [timeStamp]" }, + {"{\"type\":\"object\",\"required\":[\"msgContent\"]}", "Missing required field [msgContent]" }, + {"{\"properties\":{\"ver\":{\"type\":\"integer\"}}}", "[ver] should be an integer value" }, + {"{\"properties\":{\"cryptoType\":{\"type\":\"integer\"}}}", "[cryptoType] should be an integer value"}, + {"{\"properties\":{\"cryptoType\":{\"minimum\":0,\"maximum\":4}}}", "Undefined type in field [cryptoType]" }, + {"{\"properties\":{\"timeStamp\":{\"type\":\"integer\"}}}", "[timeStamp] should be an integer value" }, +}; + +const char *proto_schema_validation(const char *pJsonStr) { + int i; + + json_object *pJs = json_tokener_parse(pJsonStr); + + if (!pJs) { + cJSON *pRspRoot = cJSON_CreateObject(); + cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_PARSE_OBJ); + cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_PARSE_OBJ)); + return proto_create_new(pRspRoot, 200); + } + + for (i = 0; i < ARRAY_SIZE(g_json_sch); i++) { + json_object *pSc = json_tokener_parse(g_json_sch[i].pSchJson); + + if (!pSc) { + LOG_MOD(error, ZLOG_MOD_PROTO, "Json schema format error: [%s]\n", g_json_sch[i].pSchJson); + continue; + } + + if (jdac_validate(pJs, pSc) != JDAC_ERR_VALID) { + cJSON *pRspRoot = cJSON_CreateObject(); + cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_VALID_SCH); + cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_VALID_SCH)); + cJSON_AddStringToObject(pRspRoot, "details", g_json_sch[i].pErrMsg); + json_object_put(pSc); + json_object_put(pJs); + return proto_create_new(pRspRoot, 200); + } + + json_object_put(pSc); + } + + json_object_put(pJs); + return NULL; +} + +const char *proto_msg_validation(const char *pJsonStr, const char *msgJson, const char *errMsg) { + json_object *pJs = json_tokener_parse(pJsonStr); + if (!pJs) { + cJSON *pRspRoot = cJSON_CreateObject(); + cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_PARSE_OBJ); + cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_PARSE_OBJ)); + return proto_create_new(pRspRoot, 200); + } + + json_object *pSc = json_tokener_parse(msgJson); + if (!pSc) { + LOG_MOD(error, ZLOG_MOD_PROTO, "Json schema format error: [%s]\n", msgJson); + } + + if (jdac_validate(pJs, pSc) != JDAC_ERR_VALID) { + cJSON *pRspRoot = cJSON_CreateObject(); + cJSON_AddNumberToObject(pRspRoot, "status", ERR_JSON_VALID_SCH); + cJSON_AddStringToObject(pRspRoot, "message", getErrorEnumDesc(ERR_JSON_VALID_SCH)); + cJSON_AddStringToObject(pRspRoot, "details", errMsg); + json_object_put(pSc); + json_object_put(pJs); + return proto_create_new(pRspRoot, 200); + } + + json_object_put(pSc); + json_object_put(pJs); + return NULL; +} +#endif + +const char *proto_decode_context(const char *pString, unsigned int *pVer, unsigned long long *pTm, int *pErrCode) { cJSON *pMsgCtx; unsigned char *pBase64; int decodeSize; unsigned int outSize = 0; char *pMsgContent = NULL; - cJSON *pRoot = cJSON_Parse(pString); + cJSON *pRoot; +#ifdef JSON_SCHEMA_ON + const char *pSchJson; +#endif + if (pErrCode == NULL) { + return NULL; + } + + if (pString == NULL || strlen(pString) == 0) { + *pErrCode = ERR_INPUT_PARAMS; + return NULL; + } + + LOG_MOD(debug, ZLOG_MOD_PROTO, "Request: %s\n", pString); + +#ifdef JSON_SCHEMA_ON + pSchJson = proto_schema_validation(pString); + if (pSchJson != NULL && strlen(pSchJson) > 0) { + *pErrCode = ERR_JSON_VALID_SCH; + return pSchJson; + } +#endif + + pRoot = cJSON_Parse(pString); if (!pRoot) { return NULL; } @@ -201,7 +310,7 @@ const char *proto_create_new(cJSON *pMsgCtx, int httpCode) { } pStrProto = cJSON_PrintUnformatted(pRoot); - LOG_MOD(trace, ZLOG_MOD_PROTO, "Create: \n%s\n", pStrProto); + LOG_MOD(debug, ZLOG_MOD_PROTO, "Create: %s\n", pStrProto); cJSON_Delete(pRoot); diff --git a/srcs/libs/zlog_module/zlog_module.c b/srcs/libs/zlog_module/zlog_module.c index b739cb2..647d921 100644 --- a/srcs/libs/zlog_module/zlog_module.c +++ b/srcs/libs/zlog_module/zlog_module.c @@ -4,6 +4,7 @@ #include #include "zlog_module.h" #include "misc.h" +#include "config.h" #define MAX_ZLOG_MOD_LEN (8) @@ -20,6 +21,22 @@ static ZLOG_MODULE g_zlogModule[] = { DEF_ZLOG_MOD(GENERATE_ENUM_ARRAY) {-1, ZLOG_LEVEL_FATAL, NULL, "UNKNOWN"} }; +#ifdef USERVNI_ON +static char g_vni_str[64] = {0}; + +const char *zlog_vni_tag_get() { + if (strlen(g_vni_str) == 0) { + sprintf(g_vni_str, "%u", cfg_get_user_vni_id()); + } + + return (const char *)g_vni_str; +} +#else +const char *zlog_vni_tag_get() { + return "main"; +} +#endif + zlog_category_t *zlog_get_mod_cat(ZLOG_MOD_NAME logMod) { if (logMod >= ARRAY_SIZE(g_zlogModule) || logMod < 0) { logMod = ARRAY_SIZE(g_zlogModule) - 1; diff --git a/srcs/opendhcp183/opendhcpd.cpp b/srcs/opendhcp183/opendhcpd.cpp index 878f1ac..2cc5233 100644 --- a/srcs/opendhcp183/opendhcpd.cpp +++ b/srcs/opendhcp183/opendhcpd.cpp @@ -1904,18 +1904,33 @@ MYDWORD sdmess(data9 *req) { req->dhcpp.header.bp_op = BOOTP_REPLY; errno = 0; +#if DISCOVER_RSP_NOT_BOARDCAST sockaddr_in cliAddr = get_cliAddr(nicif, tempbuff, req); - +#endif if (req->req_type == DHCP_MESS_DISCOVER && !req->remote.sin_addr.s_addr) { req->bytes = (int)sendto(network.dhcpConn[req->sockInd].sock, req->raw, packSize, MSG_DONTROUTE, +#if DISCOVER_RSP_NOT_BOARDCAST (sockaddr *)&cliAddr, sizeof(cliAddr)); +#else + (sockaddr *)&req->remote, + sizeof(req->remote)); +#endif } else { - req->bytes = (int) - sendto(network.dhcpConn[req->sockInd].sock, req->raw, packSize, 0, (sockaddr *)&cliAddr, sizeof(cliAddr)); + req->bytes = (int)sendto(network.dhcpConn[req->sockInd].sock, + req->raw, + packSize, + 0, +#if DISCOVER_RSP_NOT_BOARDCAST + (sockaddr *)&cliAddr, + sizeof(cliAddr)); +#else + (sockaddr *)&req->remote, + sizeof(req->remote)); +#endif } if (errno || req->bytes <= 0) { diff --git a/srcs/opendhcp183/opendhcpd.h b/srcs/opendhcp183/opendhcpd.h index 1dec740..01334b2 100644 --- a/srcs/opendhcp183/opendhcpd.h +++ b/srcs/opendhcp183/opendhcpd.h @@ -39,7 +39,7 @@ #endif #ifndef SIOCGIFCONF -#include +#include #endif #ifndef _UIO_H_ @@ -70,19 +70,21 @@ typedef struct in_pktinfo IN_PKTINFO; #define IFF_DYNAMIC 0x8000 #endif -#define MYWORD unsigned short -#define MYBYTE unsigned char -#define MYDWORD unsigned int -#define SOCKET_ERROR -1 -#define INVALID_SOCKET -1 -#define SOCKADDR_IN sockaddr_in -#define SOCKADDR sockaddr -#define SOCKET int -#define BOOL bool -#define LPSOCKADDR sockaddr * -#define closesocket close +#define MYWORD unsigned short +#define MYBYTE unsigned char +#define MYDWORD unsigned int +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 +#define SOCKADDR_IN sockaddr_in +#define SOCKADDR sockaddr +#define SOCKET int +#define BOOL bool +#define LPSOCKADDR sockaddr * +#define closesocket close -#define STR2INT(val) ((int)strtol((val), nullptr, 10)) +#define STR2INT(val) ((int)strtol((val), nullptr, 10)) + +#define DISCOVER_RSP_NOT_BOARDCAST (0) #define logDHCPMess(logBuff, logLevel) \ do { \ @@ -705,75 +707,77 @@ struct data15 { }; //Function Prototypes -bool checkIP(data9 *req, data17 *rangeData, MYDWORD ip); -bool checkMask(MYDWORD); -bool checkRange(data17 *, char); -bool detectChange(); -bool getSection(const char *, char *, MYBYTE, char *); -bool isInt(char *); -bool isIP(char *); -FILE *openSection(const char *, MYBYTE); -MYBYTE pIP(void *, MYDWORD); -MYBYTE pUInt(void *raw, MYDWORD data); -MYBYTE pUShort(void *, MYWORD); -MYBYTE addServer(MYDWORD *, MYBYTE, MYDWORD); -int getRangeInd(MYDWORD); -char *myTrim(char *, char *); -char *myGetToken(char *, MYBYTE); -char *cloneString(char *); -char *getHexValue(MYBYTE *, char *, MYBYTE *); -char *genHostName(char *, const MYBYTE *, MYBYTE); -char *hex2String(char *, const MYBYTE *, MYBYTE); -char *IP2String(char *, MYDWORD); -char *myUpper(char *string); -char *myLower(char *string); -char *readSection(char *, FILE *); -data7 *findDHCPEntry(char *); -data7 *createCache(data71 *pLump); -MYDWORD alad(data9 *); -MYDWORD resad(data9 *); -MYDWORD sdmess(data9 *); -MYDWORD sendRepl(data9 *req); -MYDWORD *findServer(MYDWORD *, MYBYTE, MYDWORD); -int getIndex(char, MYDWORD); -int addDHCPRange(char *dp); -void addVendClass(MYBYTE rangeSetInd, char *vendClass, MYBYTE vendClassSize); -void addUserClass(MYBYTE rangeSetInd, char *userClass, MYBYTE userClassSize); -void addMacRange(MYBYTE rangeSetInd, char *macRange); -void addOptions(data9 *req); -void calcRangeLimits(MYDWORD, MYDWORD, MYDWORD *, MYDWORD *); -void closeConn(); -bool getInterfaces(data1 *pNetwork); -void *init(void *); -void lockOptions(FILE *); -void loadOptions(FILE *, const char *, data20 *); -void mySplit(char *, char *, const char *, char); -void *sendHTTP(void *); -void procHTTP(data19 *); -void pvdata(data9 *, data3 *); -void recvRepl(data9 *); -void lockIP(MYDWORD); -void sendStatus(data19 *req); -void setTempLease(data7 *); -void setLeaseExpiry(data7 *); -void setLeaseExpiry(data7 *, MYDWORD); -void *updateStateFile(void *); -MYWORD fUShort(void *); -MYWORD gdmess(data9 *, MYBYTE); -MYWORD myTokenize(char *, char *, const char *, bool); -MYDWORD fIP(void *raw); -MYDWORD fUInt(void *raw); -int prepareUserHtmlRespStatus(const char **pRsp); +bool checkIP(data9 *req, data17 *rangeData, MYDWORD ip); +bool checkMask(MYDWORD); +bool checkRange(data17 *, char); +bool detectChange(); +bool getSection(const char *, char *, MYBYTE, char *); +bool isInt(char *); +bool isIP(char *); +FILE *openSection(const char *, MYBYTE); +MYBYTE pIP(void *, MYDWORD); +MYBYTE pUInt(void *raw, MYDWORD data); +MYBYTE pUShort(void *, MYWORD); +MYBYTE addServer(MYDWORD *, MYBYTE, MYDWORD); +int getRangeInd(MYDWORD); +char *myTrim(char *, char *); +char *myGetToken(char *, MYBYTE); +char *cloneString(char *); +char *getHexValue(MYBYTE *, char *, MYBYTE *); +char *genHostName(char *, const MYBYTE *, MYBYTE); +char *hex2String(char *, const MYBYTE *, MYBYTE); +char *IP2String(char *, MYDWORD); +char *myUpper(char *string); +char *myLower(char *string); +char *readSection(char *, FILE *); +data7 *findDHCPEntry(char *); +data7 *createCache(data71 *pLump); +MYDWORD alad(data9 *); +MYDWORD resad(data9 *); +MYDWORD sdmess(data9 *); +MYDWORD sendRepl(data9 *req); +MYDWORD *findServer(MYDWORD *, MYBYTE, MYDWORD); +int getIndex(char, MYDWORD); +int addDHCPRange(char *dp); +void addVendClass(MYBYTE rangeSetInd, char *vendClass, MYBYTE vendClassSize); +void addUserClass(MYBYTE rangeSetInd, char *userClass, MYBYTE userClassSize); +void addMacRange(MYBYTE rangeSetInd, char *macRange); +void addOptions(data9 *req); +void calcRangeLimits(MYDWORD, MYDWORD, MYDWORD *, MYDWORD *); +void closeConn(); +bool getInterfaces(data1 *pNetwork); +void *init(void *); +void lockOptions(FILE *); +void loadOptions(FILE *, const char *, data20 *); +void mySplit(char *, char *, const char *, char); +void *sendHTTP(void *); +void procHTTP(data19 *); +void pvdata(data9 *, data3 *); +void recvRepl(data9 *); +void lockIP(MYDWORD); +void sendStatus(data19 *req); +void setTempLease(data7 *); +void setLeaseExpiry(data7 *); +void setLeaseExpiry(data7 *, MYDWORD); +void *updateStateFile(void *); +MYWORD fUShort(void *); +MYWORD gdmess(data9 *, MYBYTE); +MYWORD myTokenize(char *, char *, const char *, bool); +MYDWORD fIP(void *raw); +MYDWORD fUInt(void *raw); +int prepareUserHtmlRespStatus(const char **pRsp); #ifdef HTTPSERVER_ON -void opendhcp_init_http_server(); +void opendhcp_init_http_server(); +#endif +void opendhcp_set_replication_svr(); +void opendhcp_add_ip_pool_set(); +void opendhcp_add_mac_filter(); +int process_iptv_multicast(const unsigned char *p, int size, const char *mac); +int opendhcp_add_listener(); +unsigned int opendhcp_set_lease_time(); +int getHwAddr(char *buff, char *mac); +int arpSet(const char *ifname, char *ipStr, char *mac); +#if DISCOVER_RSP_NOT_BOARDCAST +sockaddr_in get_cliAddr(char *nicif, char *tempbuff, data9 *req); #endif -void opendhcp_set_replication_svr(); -void opendhcp_add_ip_pool_set(); -void opendhcp_add_mac_filter(); -int process_iptv_multicast(const unsigned char *p, int size, const char *mac); -int opendhcp_add_listener(); -unsigned int opendhcp_set_lease_time(); -int getHwAddr(char *buff, char *mac); -int arpSet(const char *ifname, char *ipStr, char *mac); -sockaddr_in get_cliAddr(char *nicif, char *tempbuff, data9 *req); #pragma clang diagnostic pop \ No newline at end of file diff --git a/srcs/opendhcp183/query.cpp b/srcs/opendhcp183/query.cpp index df6fe05..103cda4 100644 --- a/srcs/opendhcp183/query.cpp +++ b/srcs/opendhcp183/query.cpp @@ -5,18 +5,14 @@ #include using namespace std; -#include -#include #include #include #include -#include #include #include #include "opendhcpd.h" #include "s2j/cJSON.h" #include "misc.h" -#include #include #include "config.h" #include "proto.h" @@ -25,6 +21,13 @@ using namespace std; #include "sds/sds.h" #include "inet_misc.h" #include "http_svr.h" +#include "task_manager.h" + +#if DISCOVER_RSP_NOT_BOARDCAST +#include +#include +#include +#endif extern data2 cfig; extern bool kRunning; @@ -43,38 +46,90 @@ static PIPTV_DEV_SET g_iptvNewDevs = nullptr; static PIPTV_DEV_SET g_iptvCacheDevs = nullptr; static uv_rwlock_t g_uvCacheLock; +#ifdef JSON_SCHEMA_ON +// clang-format off +typedef struct { + const char *pSchJson; + const char *pErrMsg; +} JSON_POST_CTX; + +static JSON_POST_CTX g_add_msg[] = { + {R"({"type":"object","required":["rangeSet"]})", "Missing required field [rangeSet]"}, + {R"({"properties":{"rangeSet":{"type":"array","minItems":1}}})", "No content in array [rangeSet]"}, + {R"({"properties":{"rangeSet":{"items":{"type":"object","required":["dhcpRange"]}}}})", "Missing required field [dhcpRange]"}, + {R"({"properties":{"rangeSet":{"items":{"properties":{"netmask":{"type":"string"}}}}}})", "[netmask] should be a string value"}, + {R"({"properties":{"rangeSet":{"items":{"properties":{"domainServer":{"type":"string"}}}}}})", "[domainServer] should be a string value"}, + {R"({"properties":{"rangeSet":{"items":{"properties":{"gateway":{"type":"string"}}}}}})", "[gateway] should be a string value"}, + {R"({"properties":{"rangeSet":{"items":{"properties":{"leaseTime":{"type":"integer"}}}}}})", "[leaseTime] should be an integer value"}, +// {R"({"properties":{"rangeSet":{"items":{"properties":{"dhcpRange":{"type":"string","minLength":15}}}}}})", "Error in field [dhcpRange]"} +}; + +static JSON_POST_CTX g_del_msg[] = { + {R"({"type":"object","required":["dhcpRange"]})", "Missing required field [dhcpRange]"}, + {R"({"properties":{"dhcpRange":{"type":"array","minItems":1}}})", "No content in field [dhcpRange]"}, +// {R"({"properties":{"dhcpRange":{"items":{"type":"string","minLength":15}}}})", "Error in field [dhcpRange]"} +}; + +static JSON_POST_CTX g_que_msg[] = { + {R"({"type":"object","required":["userMac"]})", "Missing required field [userMac]"}, + {R"({"properties":{"userMac":{"type":"array","minItems":1}}})", "No content in field [userMac]"}, +// {R"({"properties":{"userMac":{"items":{"type":"string","minLength":17,"maxLength":17}}}})", "Error in field [userMac]"} +}; +// clang-format on +#endif + static int dhcp_get_user_info(const char **pRsp, const char *pRequest) { char logBuff[512]; const char *pStrContent; int k; + int errCode = 0; dhcpMap::iterator p; if (pRequest == nullptr || strlen(pRequest) == 0) { - sprintf(logBuff, "Requeset Json"); + sprintf(logBuff, "Request Json"); logDHCPMess(logBuff, 1); return ERR_INPUT_PARAMS; } - pStrContent = proto_decode_context(pRequest, nullptr, nullptr); + pStrContent = proto_decode_context(pRequest, nullptr, nullptr, &errCode); if (pStrContent == nullptr) { - sprintf(logBuff, "Requeset Json error %s", pRequest); + sprintf(logBuff, "Request Json error %s", pRequest); logDHCPMess(logBuff, 1); + free((void *)pStrContent); return ERR_PROTO_DECODE; } +#ifdef JSON_SCHEMA_ON + if (errCode == ERR_JSON_VALID_SCH) { + *pRsp = pStrContent; + return ERR_SUCCESS; + } + + const char *pSchJson; + for(auto i : g_que_msg) { + pSchJson = proto_msg_validation(pStrContent, i.pSchJson, i.pErrMsg); + if (pSchJson != nullptr && strlen(pSchJson) > 0) { + *pRsp = pSchJson; + free((void *)pStrContent); + return ERR_SUCCESS; + } + } + free((void *)pSchJson); +#endif + cJSON *pRoot = cJSON_Parse(pStrContent); free((void *)pStrContent); if (!pRoot) { - return ERR_JSON_PRASE_OBJ; + return ERR_JSON_PARSE_OBJ; } cJSON *pUserMac = cJSON_GetObjectItem(pRoot, "userMac"); if (!pUserMac) { cJSON_Delete(pRoot); - return ERR_JSON_PRASE_OBJ; + return ERR_JSON_PARSE_OBJ; } cJSON *pRspMsg = cJSON_CreateObject(); @@ -318,26 +373,46 @@ static int add_dhcpd_rangeset(const char **pRsp, const char *pRequest) { OBJ_DHCP_RNG range; cJSON *pRspRoot; cJSON *pExpandArray; + int errCode = 0; if (pRequest == nullptr || strlen(pRequest) == 0) { - sprintf(logBuff, "Requeset Json"); + sprintf(logBuff, "Request Json"); logDHCPMess(logBuff, 1); return ERR_INPUT_PARAMS; } - pStrContent = proto_decode_context(pRequest, nullptr, nullptr); + pStrContent = proto_decode_context(pRequest, nullptr, nullptr, &errCode); if (pStrContent == nullptr) { - sprintf(logBuff, "Requeset Json error %s", pRequest); + sprintf(logBuff, "Request Json error %s", pRequest); logDHCPMess(logBuff, 1); + free((void *)pStrContent); return ERR_PROTO_DECODE; } +#ifdef JSON_SCHEMA_ON + if (errCode == ERR_JSON_VALID_SCH) { + *pRsp = pStrContent; + return ERR_SUCCESS; + } + + const char *pSchJson; + for(auto i : g_add_msg) { + pSchJson = proto_msg_validation(pStrContent, i.pSchJson, i.pErrMsg); + if (pSchJson != nullptr && strlen(pSchJson) > 0) { + *pRsp = pSchJson; + free((void *)pStrContent); + return ERR_SUCCESS; + } + } + free((void *)pSchJson); +#endif + cJSON *pRoot = cJSON_Parse(pStrContent); free((void *)pStrContent); if (!pRoot) { - return ERR_JSON_PRASE_OBJ; + return ERR_JSON_PARSE_OBJ; } cJSON *prange_set = cJSON_GetObjectItem(pRoot, "rangeSet"); @@ -417,24 +492,44 @@ static int delete_dhcpd_rangeset(const char **pRsp, const char *pRequest) { data13 dhcpRanges[MAX_DHCP_RANGES]; PHASH_MAP delMap = nullptr; int resCount = 0; + int errCode = 0; if (pRequest == nullptr || strlen(pRequest) == 0) { - sprintf(logBuff, "Requeset Json"); + sprintf(logBuff, "Request Json"); logDHCPMess(logBuff, 1); return ERR_INPUT_PARAMS; } - pStrContent = proto_decode_context(pRequest, nullptr, nullptr); + pStrContent = proto_decode_context(pRequest, nullptr, nullptr, &errCode); if (pStrContent == nullptr) { - sprintf(logBuff, "Requeset Json error %s", pRequest); + sprintf(logBuff, "Request Json error %s", pRequest); logDHCPMess(logBuff, 1); + free((void*)pStrContent); return ERR_PROTO_DECODE; } +#ifdef JSON_SCHEMA_ON + if (errCode == ERR_JSON_VALID_SCH) { + *pRsp = pStrContent; + return ERR_SUCCESS; + } + + const char *pSchJson; + for(auto i : g_del_msg) { + pSchJson = proto_msg_validation(pStrContent, i.pSchJson, i.pErrMsg); + if (pSchJson != nullptr && strlen(pSchJson) > 0) { + *pRsp = pSchJson; + free((void*)pStrContent); + return ERR_SUCCESS; + } + } + free((void*)pSchJson); +#endif + cJSON *pRoot = cJSON_Parse(pStrContent); free((void *)pStrContent); if (!pRoot) { - return ERR_JSON_PRASE_OBJ; + return ERR_JSON_PARSE_OBJ; } cJSON *pdhcp_range = cJSON_GetObjectItem(pRoot, "dhcpRange"); @@ -443,11 +538,11 @@ static int delete_dhcpd_rangeset(const char **pRsp, const char *pRequest) { pdelArray = cJSON_CreateArray(); cJSON_AddItemToObject(pRspRoot, "rangeSet", pdelArray); + char start[128]; + char end[128]; + char del_range[256]; for (int i = 0; i < cJSON_GetArraySize(pdhcp_range); i++) { - cJSON *pdel_Item = cJSON_CreateObject(); cJSON *pdelRange = cJSON_GetArrayItem(pdhcp_range, i); - char del_range[256]; - auto *delItem = (PHASH_MAP)malloc(sizeof(HASH_MAP)); if (!pdelRange) { continue; @@ -457,42 +552,40 @@ static int delete_dhcpd_rangeset(const char **pRsp, const char *pRequest) { MYDWORD st_addr; MYDWORD en_addr; - char start[128]; - char end[128]; mySplit(start, end, del_range, '-'); - st_addr = htonl(inet_addr(start)); - en_addr = htonl(inet_addr(end)); - if (en_addr == 0) { - cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); + if(isIP(start) && isIP(end)) { + st_addr = htonl(inet_addr(start)); + en_addr = htonl(inet_addr(end)); + + PHASH_MAP s; + HASH_FIND_INT(delMap, &st_addr, s); + if (s == nullptr) { + s = (PHASH_MAP)malloc(sizeof(HASH_MAP)); + s->key = st_addr; + s->value = en_addr; + HASH_ADD_INT(delMap, key, s); + } + } else { + cJSON *pdel_Item = cJSON_CreateObject(); + cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); cJSON_AddNumberToObject(pdel_Item, "status", ERR_INPUT_PARAMS); cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_INPUT_PARAMS)); cJSON_AddItemToArray(pdelArray, pdel_Item); } - - HASH_FIND_INT(delMap, &st_addr, delItem); - if (delItem == nullptr) { - auto *s = (PHASH_MAP)malloc(sizeof(HASH_MAP)); - s->key = st_addr; - s->value = en_addr; - HASH_ADD_INT(delMap, key, s); - } } for (int i = 0; i < cfig.rangeCount; i++) { cJSON *pdel_Item = cJSON_CreateObject(); PHASH_MAP delRange; - char del_range[256]; - char saddr[128]; - char eaddr[128]; memset(del_range, 0, 256); HASH_FIND_INT(delMap, &cfig.dhcpRanges[i].rangeStart, delRange); if (delRange != nullptr) { - IP2String(saddr, ntohl(delRange->key)); - IP2String(eaddr, ntohl(delRange->value)); + IP2String(start, ntohl(delRange->key)); + IP2String(end, ntohl(delRange->value)); - sprintf(del_range, "%s-%s", saddr, eaddr); + sprintf(del_range, "%s-%s", start, end); cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); //Determine whether the input is correct or not if (delRange->value == cfig.dhcpRanges[i].rangeEnd) { @@ -500,6 +593,9 @@ static int delete_dhcpd_rangeset(const char **pRsp, const char *pRequest) { cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_SUCCESS)); cJSON_AddItemToArray(pdelArray, pdel_Item); + free(cfig.dhcpRanges[i].options); + free(cfig.dhcpRanges[i].expiry); + free(cfig.dhcpRanges[i].dhcpEntry); } else { memcpy(&dhcpRanges[resCount], &cfig.dhcpRanges[i], sizeof(struct data13)); resCount++; @@ -509,32 +605,32 @@ static int delete_dhcpd_rangeset(const char **pRsp, const char *pRequest) { } HASH_DEL(delMap, delRange); + free(delRange); } else { memcpy(&dhcpRanges[resCount], &cfig.dhcpRanges[i], sizeof(struct data13)); resCount++; + + cJSON_Delete(pdel_Item); } } //The input parameter does not exist - if (resCount > cfig.rangeCount - cJSON_GetArraySize(pdhcp_range)) { - auto *s = (PHASH_MAP)malloc(sizeof(HASH_MAP)); - PHASH_MAP tmp; - char saddr[128]; - char eaddr[128]; - char del_range[256]; - memset(del_range, 0, 256); + PHASH_MAP s; + PHASH_MAP tmp; + memset(del_range, 0, 256); + HASH_ITER(hh, delMap, s, tmp) HASH_ITER(hh, delMap, s, tmp) { + cJSON *pdel_Item = cJSON_CreateObject(); + IP2String(start, ntohl(s->key)); + IP2String(end, ntohl(s->value)); - HASH_ITER(hh, delMap, s, tmp) { - cJSON *pdel_Item = cJSON_CreateObject(); - IP2String(saddr, ntohl(s->key)); - IP2String(eaddr, ntohl(s->value)); + sprintf(del_range, "%s-%s", start, end); + cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); - sprintf(del_range, "%s-%s", saddr, eaddr); - cJSON_AddStringToObject(pdel_Item, "dhcpRange", del_range); + cJSON_AddNumberToObject(pdel_Item, "status", ERR_ITEM_UNEXISTS); + cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_ITEM_UNEXISTS)); + cJSON_AddItemToArray(pdelArray, pdel_Item); - cJSON_AddNumberToObject(pdel_Item, "status", ERR_ITEM_UNEXISTS); - cJSON_AddStringToObject(pdel_Item, "message", getErrorEnumDesc(ERR_ITEM_UNEXISTS)); - cJSON_AddItemToArray(pdelArray, pdel_Item); - } + HASH_DEL(delMap, s); + free(s); } //Rewrite cfig.dhcpRanges @@ -658,6 +754,7 @@ int getHwAddr(char *buff, char *mac) { #pragma clang diagnostic pop +#if DISCOVER_RSP_NOT_BOARDCAST int arpSet(const char *ifname, char *ipStr, char *mac) { if (ifname == nullptr || ipStr == nullptr || mac == nullptr) { LOG_MOD(error, ZLOG_MOD_OPENDHCPD, "para is null.\n"); @@ -707,6 +804,7 @@ sockaddr_in get_cliAddr(char *nicif, char *tempbuff, data9 *req) { cliAddr.sin_addr.s_addr = inet_addr(IP2String(tempbuff, req->dhcpp.header.bp_yiaddr)); return cliAddr; } +#endif unsigned int opendhcp_set_lease_time() { return config_get_dhcp_server_lease_time(); @@ -749,60 +847,63 @@ static void on_http_response_cb(void *pData, free(pUserData); } -void iptvCacheCb(void *UNUSED(pArg)) { - do { - bool isReport = false; - const char *pUrl = config_get_agent_iptv_report_url(); - PIPTV_DEV_SET report = nullptr; - PIPTV_DEV_SET pDev, pTmp = nullptr; - uv_rwlock_wrlock(&g_uvCacheLock); - HASH_ITER(hh, g_iptvNewDevs, pDev, pTmp) { - PIPTV_DEV_SET pTemp; - const char *pDevMac = strdup(pDev->iptvMAC); - HASH_FIND_STR(g_iptvCacheDevs, pDevMac, pTemp); - // 新发现设备没有被上报过 - if (!pTemp) { - auto pCacheDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); - memcpy(pCacheDev, pDev, sizeof(IPTV_DEV_SET)); - HASH_ADD_STR(report, iptvMAC, pCacheDev); +void iptvCacheCb(uv_timer_t *UNUSED(pArg)) { + bool isReport = false; + const char *pUrl = config_get_agent_iptv_report_url(); + PIPTV_DEV_SET report = nullptr; + PIPTV_DEV_SET pDev, pTmp = nullptr; + uv_rwlock_wrlock(&g_uvCacheLock); + HASH_ITER(hh, g_iptvNewDevs, pDev, pTmp) uv_sleep(10); + HASH_ITER(hh, report, pDev, pTmp) { + HASH_DEL(report, pDev); + free(pDev); + } + HASH_ITER(hh, report, pDev, pTmp) if (isReport && pUrl && strlen(pUrl) > 0) { + cJSON *pRspMsg = cJSON_CreateObject(); + cJSON *pMsgArray = cJSON_CreateArray(); + cJSON_AddItemToObject(pRspMsg, "iptvDevs", pMsgArray); - isReport = true; - // 添加到缓存列表供后续查询 - HASH_ADD_STR(g_iptvCacheDevs, iptvMAC, pCacheDev); - LOG_MOD(debug, - ZLOG_MOD_OPENDHCPD, - "Add IPTV device %s vni %d to cache\n", - pCacheDev->iptvMAC, - pCacheDev->vni); - } - - HASH_DEL(g_iptvNewDevs, pDev); - free(pDev); - free((void *)pDevMac); - } - uv_rwlock_wrunlock(&g_uvCacheLock); - - if (isReport && pUrl && strlen(pUrl) > 0) { - cJSON *pRspMsg = cJSON_CreateObject(); - cJSON *pMsgArray = cJSON_CreateArray(); - cJSON_AddItemToObject(pRspMsg, "iptvDevs", pMsgArray); - - HASH_ITER(hh, report, pDev, pTmp) { - cJSON *pRspItem = cJSON_CreateObject(); - cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); - cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); - pDev->isReport = 1; - cJSON_AddItemToArray(pMsgArray, pRspItem); - } - - const char *pStrPro = proto_create_new(pRspMsg, 200); - - // Report new IPTV device MAC - inet_http_post_async(pUrl, pStrPro, on_http_response_cb, (void *)pStrPro); + HASH_ITER(hh, report, pDev, pTmp) { + cJSON *pRspItem = cJSON_CreateObject(); + cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); + cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); + pDev->isReport = 1; + cJSON_AddItemToArray(pMsgArray, pRspItem); } - uv_sleep(10); - } while (true); + const char *pStrPro = proto_create_new(pRspMsg, 200); + + // Report new IPTV device MAC + inet_http_post_async(pUrl, pStrPro, on_http_response_cb, (void *)pStrPro); + } + uv_rwlock_wrunlock(&g_uvCacheLock); + HASH_ITER(hh, g_iptvNewDevs, pDev, pTmp) { + PIPTV_DEV_SET pTemp; + const char *pDevMac = strdup(pDev->iptvMAC); + HASH_FIND_STR(g_iptvCacheDevs, pDevMac, pTemp); + // 新发现设备没有被上报过 + if (!pTemp) { + auto pCacheDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); + auto pRepDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); + + memcpy(pCacheDev, pDev, sizeof(IPTV_DEV_SET)); + memcpy(pRepDev, pDev, sizeof(IPTV_DEV_SET)); + HASH_ADD_STR(report, iptvMAC, pRepDev); + + isReport = true; + // 添加到缓存列表供后续查询 + HASH_ADD_STR(g_iptvCacheDevs, iptvMAC, pCacheDev); + LOG_MOD(debug, + ZLOG_MOD_OPENDHCPD, + "Add IPTV device %s vni %d to cache\n", + pCacheDev->iptvMAC, + pCacheDev->vni); + } + + HASH_DEL(g_iptvNewDevs, pDev); + free(pDev); + free((void *)pDevMac); + } } /** @@ -924,12 +1025,13 @@ static HTTP_ROUTE_INFO g_routeTable[] = { }; void opendhcp_init_http_server() { - static int added = FALSE; - static uv_thread_t uvThread; - + static int added = FALSE; + static uv_timer_t uvTm; if (!added) { uv_rwlock_init(&g_uvCacheLock); - uv_thread_create(&uvThread, iptvCacheCb, nullptr); + uv_timer_init(get_task_manager(), &uvTm); + + uv_timer_start(&uvTm, iptvCacheCb, 1000, 1000); for (auto &i : g_routeTable) { PHTTP_ROUTE_INFO p = &i; http_add_route(p->routeName, p->method, p->priority, p->cb, p->pUserData); diff --git a/srcs/vcpe_main.c b/srcs/vcpe_main.c index 2fb59f3..409781b 100644 --- a/srcs/vcpe_main.c +++ b/srcs/vcpe_main.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "cmdline.h" #include "task_manager.h" #include "init.h" @@ -76,7 +77,9 @@ static void on_http_response_cb(void *pData, } int main(int argc, char **argv) { - int ret; + int ret; + const char *pRspUrl; + #ifdef OPENDHCPDDNS_ON return dual_server_main(argc, argv); #else @@ -103,12 +106,19 @@ int main(int argc, char **argv) { pppoe_session_init(); #endif - const char *pStrSetup = proto_create_new(create_app_process_status(1), 200); - inet_http_post_async(config_get_agent_moniter_report_url(), pStrSetup, on_http_response_cb, (void *)pStrSetup); + pRspUrl = config_get_agent_moniter_report_url(); + + if (pRspUrl && strlen(pRspUrl) > 0) { + const char *pStrSetup = proto_create_new(create_app_process_status(1), 200); + inet_http_post_async(config_get_agent_moniter_report_url(), pStrSetup, on_http_response_cb, (void *)pStrSetup); + } + task_manager_run(); - const char *pStrExit = proto_create_new(create_app_process_status(0), 200); - inet_http_post_async(config_get_agent_moniter_report_url(), pStrSetup, on_http_response_cb, (void *)pStrExit); + if (pRspUrl && strlen(pRspUrl) > 0) { + const char *pStrExit = proto_create_new(create_app_process_status(0), 200); + inet_http_post_async(config_get_agent_moniter_report_url(), pStrExit, on_http_response_cb, (void *)pStrExit); + } while (!is_system_cleanup()) { sleep(1); diff --git a/unit_test/CMakeLists.txt b/unit_test/CMakeLists.txt index 43f1b8e..35b590e 100644 --- a/unit_test/CMakeLists.txt +++ b/unit_test/CMakeLists.txt @@ -8,7 +8,7 @@ ADD_DEFINITIONS(-DPROJECT_NAME="${PROJECT_NAME}") ADD_EXECUTABLE(${PROJECT_NAME} ${UTEST_SRC}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} common) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} common ${COMMON_LIBS}) #INCLUDE(CTest) #INCLUDE(doctest) diff --git a/unit_test/crypto/crypto_test.cpp b/unit_test/crypto/crypto_test.cpp new file mode 100644 index 0000000..afbfae1 --- /dev/null +++ b/unit_test/crypto/crypto_test.cpp @@ -0,0 +1,47 @@ +// +// Created by dongwenzhe on 2023/3/14. +// +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" +#include "crypto.h" + +TEST_SUITE("Crypto functions") { + TEST_CASE("BASE64") { + auto *pSrc = (unsigned char *)"HELLOWORLD"; + const char *encode; + + encode = base64_encode(pSrc, 16); + INFO("BASE64_ENCODING:", encode); + + unsigned char *decode; + unsigned int outputSize = 0; + decode = base64_decode(encode, &outputSize); + INFO("BASE64_DECODING:", decode); + + for(int i = 0; inCores, 0); + CHECK_NE(cpuInfo->cpuUsed, 0); + CHECK_NE(cpuInfo->cpuCoreDesc.cpuName, nullptr); + } +} diff --git a/unit_test/json/json_validator.cpp b/unit_test/json/json_validator.cpp new file mode 100644 index 0000000..85edb24 --- /dev/null +++ b/unit_test/json/json_validator.cpp @@ -0,0 +1,54 @@ +// +// Created by xajhuang on 2023/2/23. +// +#include "doctest.h" +#ifdef __cplusplus +extern "C" { +#endif +#include "json_schema/jsoncdaccord.h" +#ifdef __cplusplus +} +#endif + +TEST_SUITE("Json schema validator functions") { + TEST_CASE("JSONCDAC VALIDATOR") { + const char *json = + "{\n" + " \"ver\": 3,\n" + " \"cryptoType\": 0,\n" + " \"timeStamp\": 1599187216753,\n" + " \"msgContent\": {\n" + " \"rangeSet\": [\n" + " {\n" + " \"dhcpRange\": \"192.168.30.50-192.168.30.60\",\n" + " \"netmask\": \"255.255.255.0\",\n" + " \"domainServer\": \"114.114.114.114, 8.8.8.8\",\n" + " \"gateway\": \"192.168.30.1\",\n" + " \"leaseTime\": 420\n" + " }\n" + " ]\n" + " }\n" + "}"; + + const char *sch = + "{\n" + "\t\"type\": \"object\",\n" + "\t\"properties\": {\n" + "\t\t\"ver\": {\n" + "\t\t\t\"type\": \"string\"\t\t\t\n" + "\t\t}\n" + "\t},\n" + "\t\"required\": [\n" + " \"ver\"\n" + " ]\n" + "}"; + + json_object *pJs = json_tokener_parse(json); + json_object *pSc = json_tokener_parse(sch); + + CHECK_NE(pJs, nullptr); + CHECK_NE(pSc, nullptr); + int ret = jdac_validate(pJs, pSc); + CHECK_EQ(JDAC_ERR_VALID, ret); + } +} \ No newline at end of file diff --git a/unit_test/s2j/s2j_test.cpp b/unit_test/s2j/s2j_test.cpp new file mode 100644 index 0000000..3521f0b --- /dev/null +++ b/unit_test/s2j/s2j_test.cpp @@ -0,0 +1,58 @@ +// +// Created by dongwenzhe on 2023/3/17. +// +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "doctest.h" +#include "s2j/s2j.h" + +typedef struct { + char info[16]; +} Message; + +typedef struct { + int id; + char name[16]; + Message msg; +} Service; + +TEST_SUITE("S2J_TEST") { + TEST_CASE("S2J") { + Service origin_Server; + origin_Server.id = 3; + strcpy(origin_Server.name, "dhcpServer"); + strcpy(origin_Server.msg.info, "opendhcpd"); + Service *pServer = &origin_Server; + + s2j_create_json_obj(testServer); + s2j_json_set_basic_element(testServer, pServer, int, id); + s2j_json_set_basic_element(testServer, pServer, string, name); + s2j_json_set_struct_element(testInfo, testServer, pMsg, pServer, Message, msg); + s2j_json_set_basic_element(testInfo, pMsg, string, info); + + int i; + CHECK_EQ(testServer->child->valueint, 3); + for(i = 0; i < strlen(origin_Server.name); i++) { + CHECK_EQ(origin_Server.name[i], testServer->child->next->valuestring[i]); + } + for(i = 0; i < strlen(origin_Server.msg.info); i++) { + CHECK_EQ(origin_Server.msg.info[i], testServer->child->next->next->child->valuestring[i]); + } + + cJSON_Delete(testServer); + } + + TEST_CASE("J2S") { + char originServer[] = R"({"id":3, "name":"dhcpServer", "message":{"info":"opendhcpd"}})"; + cJSON *testServer = cJSON_Parse(originServer); + + s2j_create_struct_obj(pServer, Service); + s2j_struct_get_basic_element(pServer, testServer, int, id); + s2j_struct_get_basic_element(pServer, testServer, string, name); + s2j_struct_get_struct_element(pMsg, pServer, testInfo, testServer, Message, msg); + s2j_struct_get_basic_element(pMsg, testInfo, string, info); + + CHECK_EQ(pServer->id, 3); + cJSON_Delete(testServer); + free(pServer); + } +} diff --git a/unit_test/uthash/utarray_test.cpp b/unit_test/uthash/utarray_test.cpp new file mode 100644 index 0000000..be26e9b --- /dev/null +++ b/unit_test/uthash/utarray_test.cpp @@ -0,0 +1,51 @@ +// +// Created by dongwenzhe on 2023/3/21. +// +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "uthash/utarray.h" +#include "doctest.h" + +typedef struct { + int a; + char *b; +} COMBO,*PCOMBO; + +UT_icd ut_combo_icd = {sizeof(COMBO), nullptr, nullptr, nullptr}; + +TEST_SUITE("UTArray") { + UT_array *nums; + COMBO t_combo; + + TEST_CASE("PUSH") { + PCOMBO p_combo; + memset(&p_combo, 0, sizeof(PCOMBO)); + + utarray_new(nums, &ut_combo_icd); + + t_combo.a = 1; + t_combo.b = "hello "; + utarray_push_back(nums, &t_combo); + t_combo.a = 2; + t_combo.b = "world"; + utarray_push_back(nums, &t_combo); + + while((PCOMBO)utarray_next(nums, p_combo) != nullptr) { + p_combo = (PCOMBO)utarray_next(nums, p_combo); + MESSAGE("COMBO:", p_combo->a); + MESSAGE(doctest::String(p_combo->b)); + } + } + + TEST_CASE("POP") { + PCOMBO p_combo; + memset(&p_combo, 0, sizeof(PCOMBO)); + MESSAGE("original len: ", utarray_len(nums)); + while(utarray_len(nums) != 0) { + p_combo = (PCOMBO)utarray_next(nums, p_combo); + utarray_pop_back(nums); + MESSAGE("len: ", utarray_len(nums)); + } + + utarray_free(nums); + } +} \ No newline at end of file diff --git a/unit_test/uthash/utstring_test.cpp b/unit_test/uthash/utstring_test.cpp new file mode 100644 index 0000000..3a789ee --- /dev/null +++ b/unit_test/uthash/utstring_test.cpp @@ -0,0 +1,46 @@ +// +// Created by dongwenzhe on 2023/3/21. +// + +//#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN +#include "uthash/utstring.h" +#include "doctest.h" + +TEST_SUITE("UTString") { + + TEST_CASE("Append") { + UT_string *s; + UT_string *t; + + utstring_new(s); + utstring_new(t); + utstring_printf(s, "hello "); + utstring_printf(t, "world"); + + utstring_concat(s, t); + char *body = utstring_body(s); + + MESSAGE(doctest::String(body)); + CHECK(doctest::String(body) == "hello world"); + + utstring_free(s); + utstring_free(t); + } + + TEST_CASE("Binary") { + UT_string *s; + utstring_new(s); + utstring_printf(s, "hello world"); + MESSAGE(utstring_len(s)); + + char binary[] = "\xff\xff"; + utstring_bincpy(s, binary, sizeof(binary)); + MESSAGE(utstring_len(s)); + char *body = utstring_body(s); + MESSAGE(doctest::String(body)); + + utstring_clear(s); + + utstring_free(s); + } +} \ No newline at end of file