diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e8338f2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "configurations": [ + { + "type": "cmake", + "request": "launch", + "name": "Debug portfile(s)", + "cmakeDebugType": "external", + "pipeName": "\\\\.\\pipe\\vcpkg_ext_portfile_dbg", + "preLaunchTask": "Debug vcpkg commands" + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fa1fcba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required (VERSION 3.8) + +if (POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") +endif() + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +project ("EtrediaEmpires") + +add_subdirectory ("p7lib") +add_subdirectory ("ECSAPI") +add_subdirectory ("frontend") \ No newline at end of file diff --git a/ECSAPI/CMakePresets.json b/CMakePresets.json similarity index 100% rename from ECSAPI/CMakePresets.json rename to CMakePresets.json diff --git a/ECSAPI/CMakeUserPresets.json b/ECSAPI/CMakeUserPresets.json deleted file mode 100644 index 15fa6aa..0000000 --- a/ECSAPI/CMakeUserPresets.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 3, - "configurePresets": [ - { - "name": "DEBUG", - "inherits": "x64-debug", - "environment": { - "VCPKG_ROOT": "E:/vcpkg/vcpkg" - } - } - ] -} \ No newline at end of file diff --git a/ECSAPI/ECS/CMakeLists.txt b/ECSAPI/ECS/CMakeLists.txt index f215987..34a8fc2 100644 --- a/ECSAPI/ECS/CMakeLists.txt +++ b/ECSAPI/ECS/CMakeLists.txt @@ -13,15 +13,15 @@ find_package(EnTT CONFIG REQUIRED) # Link library -add_library(ECS ${HEADERS} ${SOURCES}) -add_library(ECS::ECS ALIAS ECS) +add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES}) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_link_libraries(ECS PUBLIC Economy::Economy) -target_link_libraries(ECS PRIVATE EnTT::EnTT) +target_link_libraries(${PROJECT_NAME} PUBLIC Economy::Economy) +target_link_libraries(${PROJECT_NAME} PRIVATE EnTT::EnTT) -target_include_directories(ECS PUBLIC include/) +target_include_directories(${PROJECT_NAME} PUBLIC include/) if (CMAKE_VERSION VERSION_GREATER 3.12) - set_property(TARGET ECS PROPERTY CXX_STANDARD 20) + set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) endif() \ No newline at end of file diff --git a/ECSAPI/ECS/include/ee_ecs/api.hpp b/ECSAPI/ECS/include/ee_ecs/api.hpp index b7f231c..5350f05 100644 --- a/ECSAPI/ECS/include/ee_ecs/api.hpp +++ b/ECSAPI/ECS/include/ee_ecs/api.hpp @@ -5,10 +5,10 @@ namespace ee_ecs { - void init(init_configuration config); + void init(InitConfiguration config); void start(); template - const std::vector get_all_enterprises(); - //const enterprise_info get_enterprise(uint32_t id); + const std::vector getAllEnterprises(); + //const EnterpriseInfo getEnterprise(uint32_t id); } \ No newline at end of file diff --git a/ECSAPI/ECS/include/ee_ecs/data.hpp b/ECSAPI/ECS/include/ee_ecs/data.hpp index c24b3dd..a406c6d 100644 --- a/ECSAPI/ECS/include/ee_ecs/data.hpp +++ b/ECSAPI/ECS/include/ee_ecs/data.hpp @@ -6,19 +6,19 @@ namespace ee_ecs { - struct init_configuration + struct InitConfiguration { - std::unordered_map states; + std::unordered_map states; }; - struct enterprise_info + struct EnterpriseInfo { - const ee_economy::enterprise* info = nullptr; - const ee_economy::container* storage = nullptr; + const ee_economy::Enterprise* info = nullptr; + const ee_economy::Container* storage = nullptr; std::variant< - const ee_economy::miner*, - const ee_economy::deliverer* - > special_info; + const ee_economy::Miner*, + const ee_economy::Deliverer* + > specialInfo; }; } \ No newline at end of file diff --git a/ECSAPI/ECS/include/ee_ecs/world.hpp b/ECSAPI/ECS/include/ee_ecs/world.hpp index aa9e53b..649c4fc 100644 --- a/ECSAPI/ECS/include/ee_ecs/world.hpp +++ b/ECSAPI/ECS/include/ee_ecs/world.hpp @@ -7,28 +7,27 @@ namespace ee_ecs { - class world + class World { - private: entt::registry registry; - std::unordered_map states_table; + std::unordered_map statesTable; - void update_enterprises(); + void updateEnterprises(); public: // Run every registered system void update(); - entt::entity register_state(const int16_t id, const ee_economy::container &resources); + entt::entity registerState(const int16_t id, const ee_economy::Container &resources); - entt::entity spawn_enterprise( - const bool is_building, + entt::entity spawnEnterprise( + const bool isBuilding, const ee_economy::ACTION_TYPE action, const entt::entity state, - const ee_economy::enterprise_defaults &defaults + const ee_economy::EnterpriseDefaults &defaults ); - entt::registry& get_registry(); + entt::registry& getRegistry(); }; } \ No newline at end of file diff --git a/ECSAPI/ECS/src/api.cpp b/ECSAPI/ECS/src/api.cpp index a10a50e..6233eab 100644 --- a/ECSAPI/ECS/src/api.cpp +++ b/ECSAPI/ECS/src/api.cpp @@ -2,13 +2,13 @@ #include -static ee_ecs::world world_instance; +static ee_ecs::World worldInstance; -void ee_ecs::init(ee_ecs::init_configuration config) +void ee_ecs::init(ee_ecs::InitConfiguration config) { for (auto& [id, container]: config.states) { - world_instance.register_state(id, container); + worldInstance.registerState(id, container); } } @@ -18,24 +18,24 @@ void ee_ecs::start() } template - const std::vector ee_ecs::get_all_enterprises() + const std::vector ee_ecs::getAllEnterprises() { - std::vector result; + std::vector result; //TODO: REPLACE VIEWS WITH GROUPS! - auto enterprises = world_instance.get_registry().group<>(entt::get< - ee_economy::enterprise, - ee_economy::container, + auto enterprises = worldInstance.getRegistry().group<>(entt::get< + ee_economy::Enterprise, + ee_economy::Container, T >); result.reserve(enterprises.size_hint()); for (auto [entity, enterprise, container, action]: enterprises.each()) { - enterprise_info eninfo; + EnterpriseInfo eninfo; eninfo.info = &enterprise; eninfo.storage = &container; - eninfo.special_info = &action; + eninfo.specialInfo = &action; result.push_back(eninfo); } diff --git a/ECSAPI/ECS/src/world.cpp b/ECSAPI/ECS/src/world.cpp index 95e4bb6..f98e20b 100644 --- a/ECSAPI/ECS/src/world.cpp +++ b/ECSAPI/ECS/src/world.cpp @@ -2,61 +2,61 @@ #include #include -void ee_ecs::world::update_enterprises() +void ee_ecs::World::updateEnterprises() { - ee_economy::enterprise_routine(this->registry); + ee_economy::enterpriseRoutine(this->registry); ee_economy::mining(this->registry); ee_economy::delivering(this->registry); } -void ee_ecs::world::update() +void ee_ecs::World::update() { - this->update_enterprises(); + this->updateEnterprises(); } -entt::entity ee_ecs::world::register_state(const int16_t id, const ee_economy::container &resources) +entt::entity ee_ecs::World::registerState(const int16_t id, const ee_economy::Container &resources) { - if (this->states_table.contains(id)) + if (this->statesTable.contains(id)) throw std::invalid_argument("State with this Id is already registered"); entt::entity entity = this->registry.create(); - this->registry.emplace(entity, id); - this->registry.emplace( + this->registry.emplace(entity, id); + this->registry.emplace( entity, resources.capacity, resources.total, resources.content ); - this->states_table[id] = entity; + this->statesTable[id] = entity; return entity; } -entt::entity ee_ecs::world::spawn_enterprise( - const bool is_building, +entt::entity ee_ecs::World::spawnEnterprise( + const bool isBuilding, const ee_economy::ACTION_TYPE action, const entt::entity state, - const ee_economy::enterprise_defaults &defaults + const ee_economy::EnterpriseDefaults &defaults ) { entt::entity entity = this->registry.create(); - this->registry.emplace( + this->registry.emplace( entity, - is_building, + isBuilding, state, action, - defaults.base_efficiency * defaults.factor_efficiency, + defaults.baseEfficiency * defaults.factorEfficiency, - defaults.base_efficiency, - defaults.factor_efficiency + defaults.baseEfficiency, + defaults.factorEfficiency ); - this->registry.emplace( + this->registry.emplace( entity, defaults.container.capacity, defaults.container.total, @@ -67,13 +67,13 @@ entt::entity ee_ecs::world::spawn_enterprise( { case ee_economy::ACTION_TYPE::MINING: { - this->registry.emplace(entity, defaults.resource_target); + this->registry.emplace(entity, defaults.resourceTarget); break; } case ee_economy::ACTION_TYPE::DELIVERY: { - this->registry.emplace(entity, defaults.resource_target); + this->registry.emplace(entity, defaults.resourceTarget); break; } @@ -84,4 +84,4 @@ entt::entity ee_ecs::world::spawn_enterprise( return entity; } -entt::registry& ee_ecs::world::get_registry() {return this->registry;} \ No newline at end of file +entt::registry& ee_ecs::World::getRegistry() {return this->registry;} \ No newline at end of file diff --git a/ECSAPI/ECS/test/CMakeLists.txt b/ECSAPI/ECS/test/CMakeLists.txt index 0f11be0..2df383f 100644 --- a/ECSAPI/ECS/test/CMakeLists.txt +++ b/ECSAPI/ECS/test/CMakeLists.txt @@ -1,3 +1,5 @@ +project(ecs_tests) + # List sources set(SOURCES "test_conf.hpp" "main.cpp" "world.cpp" "benchmark.cpp") @@ -10,14 +12,14 @@ find_package(GTest CONFIG REQUIRED) include(GoogleTest) -add_executable(ecs_tests ${SOURCES}) -target_link_libraries(ecs_tests PRIVATE GTest::gtest_main) -target_link_libraries(ecs_tests PRIVATE ECS::ECS) +add_executable(${PROJECT_NAME} ${SOURCES}) +target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest_main) +target_link_libraries(${PROJECT_NAME} PRIVATE ECS::ECS) # Test if (CMAKE_VERSION VERSION_GREATER 3.12) - set_property(TARGET ecs_tests PROPERTY CXX_STANDARD 20) + set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) endif() -gtest_discover_tests(ecs_tests) \ No newline at end of file +gtest_discover_tests(${PROJECT_NAME}) \ No newline at end of file diff --git a/ECSAPI/ECS/test/benchmark.cpp b/ECSAPI/ECS/test/benchmark.cpp index a0a2e1e..6530535 100644 --- a/ECSAPI/ECS/test/benchmark.cpp +++ b/ECSAPI/ECS/test/benchmark.cpp @@ -17,7 +17,7 @@ private: }; template -void generic_with(Func func) { +void genericWith(Func func) { timer timer; func(); timer.elapsed(); @@ -25,7 +25,7 @@ void generic_with(Func func) { TEST_F(WorldBenchmark, UpdateSystems) { - generic_with([&]() { + genericWith([&]() { world.update(); }); } \ No newline at end of file diff --git a/ECSAPI/ECS/test/test_conf.hpp b/ECSAPI/ECS/test/test_conf.hpp index d5d1c47..4aded49 100644 --- a/ECSAPI/ECS/test/test_conf.hpp +++ b/ECSAPI/ECS/test/test_conf.hpp @@ -5,27 +5,27 @@ struct WorldBenchmark : testing::Test { - ee_ecs::world world; + ee_ecs::World world; void SetUp() { for (int16_t i = 0; i < 1000; i++) { - ee_economy::container resources = {.capacity = 100.0}; + ee_economy::Container resources = {.capacity = 100.0}; resources.add(ee_economy::RESOURCE_TYPE::COAL, 100.0); - entt::entity state = world.register_state(i, resources); + entt::entity state = world.registerState(i, resources); - ee_economy::enterprise_defaults miner = { + ee_economy::EnterpriseDefaults miner = { .container = {.capacity = 100.0}, - .resource_target = ee_economy::RESOURCE_TYPE::GOLD, - .base_efficiency = 1.0 + .resourceTarget = ee_economy::RESOURCE_TYPE::GOLD, + .baseEfficiency = 1.0 }; - world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); - world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); - world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); - world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); - world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); + world.spawnEnterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); + world.spawnEnterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); + world.spawnEnterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); + world.spawnEnterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); + world.spawnEnterprise(false, ee_economy::ACTION_TYPE::MINING, state, miner); } } diff --git a/ECSAPI/ECS/test/world.cpp b/ECSAPI/ECS/test/world.cpp index f9da1b8..3171c71 100644 --- a/ECSAPI/ECS/test/world.cpp +++ b/ECSAPI/ECS/test/world.cpp @@ -5,76 +5,76 @@ TEST(WorldTest, RegisterState) { - ee_ecs::world world; + ee_ecs::World world; - ee_economy::container res = {.capacity = 100.0}; + ee_economy::Container res = {.capacity = 100.0}; res.add(ee_economy::RESOURCE_TYPE::COAL, 98.0); - entt::entity state = world.register_state(10, res); + entt::entity state = world.registerState(10, res); - ee_economy::state registered_state = world.get_registry().get(state); - ee_economy::container registered_container = world.get_registry().get(state); + ee_economy::State registeredState = world.getRegistry().get(state); + ee_economy::Container registeredContainer = world.getRegistry().get(state); - ASSERT_EQ(registered_state.external_id, 10); - ASSERT_DOUBLE_EQ(registered_container.content[ee_economy::RESOURCE_TYPE::COAL], 98.0); + ASSERT_EQ(registeredState.externalId, 10); + ASSERT_DOUBLE_EQ(registeredContainer.content[ee_economy::RESOURCE_TYPE::COAL], 98.0); } TEST(WorldTest, RegisterStateDuplicate) { - ee_ecs::world world; + ee_ecs::World world; - world.register_state(10, {}); + world.registerState(10, {}); ASSERT_THROW({ - world.register_state(10, {}); + world.registerState(10, {}); }, std::invalid_argument); } TEST(WorldTest, SpawnMiner) { - ee_ecs::world world; + ee_ecs::World world; - entt::entity state = world.get_registry().create(); - world.get_registry().emplace(state, (int16_t)0); - world.get_registry().emplace(state, 100.0); + entt::entity state = world.getRegistry().create(); + world.getRegistry().emplace(state, (int16_t)0); + world.getRegistry().emplace(state, 100.0); - ee_economy::enterprise_defaults defaults = { + ee_economy::EnterpriseDefaults defaults = { .container = {.capacity = 100.0 }, - .resource_target = ee_economy::RESOURCE_TYPE::COAL, - .base_efficiency = 1.0, + .resourceTarget = ee_economy::RESOURCE_TYPE::COAL, + .baseEfficiency = 1.0, }; - entt::entity enterprise = world.spawn_enterprise(false, ee_economy::ACTION_TYPE::MINING, state, defaults); + entt::entity enterprise = world.spawnEnterprise(false, ee_economy::ACTION_TYPE::MINING, state, defaults); - ee_economy::enterprise registered_enterprise = world.get_registry().get(enterprise); - ee_economy::miner registered_action = world.get_registry().get(enterprise); - ee_economy::container registered_container = world.get_registry().get(enterprise); + ee_economy::Enterprise registeredEnterprise = world.getRegistry().get(enterprise); + ee_economy::Miner registeredAction = world.getRegistry().get(enterprise); + ee_economy::Container registeredContainer = world.getRegistry().get(enterprise); - ASSERT_DOUBLE_EQ(registered_enterprise.base_efficiency, 1.0); - ASSERT_EQ(registered_action.resource, ee_economy::RESOURCE_TYPE::COAL); - ASSERT_DOUBLE_EQ(registered_container.capacity, 100.0); + ASSERT_DOUBLE_EQ(registeredEnterprise.baseEfficiency, 1.0); + ASSERT_EQ(registeredAction.resource, ee_economy::RESOURCE_TYPE::COAL); + ASSERT_DOUBLE_EQ(registeredContainer.capacity, 100.0); } TEST(WorldTest, SpawnDeliverer) { - ee_ecs::world world; + ee_ecs::World world; - entt::entity state = world.get_registry().create(); - world.get_registry().emplace(state, (int16_t)0); - world.get_registry().emplace(state, 100.0); + entt::entity state = world.getRegistry().create(); + world.getRegistry().emplace(state, (int16_t)0); + world.getRegistry().emplace(state, 100.0); - ee_economy::enterprise_defaults defaults = { + ee_economy::EnterpriseDefaults defaults = { .container = {.capacity = 100.0 }, - .resource_target = ee_economy::RESOURCE_TYPE::COAL, - .base_efficiency = 1.0, + .resourceTarget = ee_economy::RESOURCE_TYPE::COAL, + .baseEfficiency = 1.0, }; - entt::entity enterprise = world.spawn_enterprise(false, ee_economy::ACTION_TYPE::DELIVERY, state, defaults); + entt::entity enterprise = world.spawnEnterprise(false, ee_economy::ACTION_TYPE::DELIVERY, state, defaults); - ee_economy::enterprise registered_enterprise = world.get_registry().get(enterprise); - ee_economy::deliverer registered_action = world.get_registry().get(enterprise); - ee_economy::container registered_container = world.get_registry().get(enterprise); + ee_economy::Enterprise registeredEnterprise = world.getRegistry().get(enterprise); + ee_economy::Deliverer registeredAction = world.getRegistry().get(enterprise); + ee_economy::Container registeredContainer = world.getRegistry().get(enterprise); - ASSERT_DOUBLE_EQ(registered_enterprise.base_efficiency, 1.0); - ASSERT_EQ(registered_action.resource, ee_economy::RESOURCE_TYPE::COAL); - ASSERT_DOUBLE_EQ(registered_container.capacity, 100.0); + ASSERT_DOUBLE_EQ(registeredEnterprise.baseEfficiency, 1.0); + ASSERT_EQ(registeredAction.resource, ee_economy::RESOURCE_TYPE::COAL); + ASSERT_DOUBLE_EQ(registeredContainer.capacity, 100.0); } \ No newline at end of file diff --git a/ECSAPI/Economy/CMakeLists.txt b/ECSAPI/Economy/CMakeLists.txt index be3931e..7e11e37 100644 --- a/ECSAPI/Economy/CMakeLists.txt +++ b/ECSAPI/Economy/CMakeLists.txt @@ -21,13 +21,13 @@ find_package(EnTT CONFIG REQUIRED) # Link library -add_library(Economy ${HEADERS} ${HEADERS_COMPONENTS} ${SOURCES} ${SOURCES_SYSTEMS}) -add_library(Economy::Economy ALIAS Economy) +add_library(${PROJECT_NAME} ${HEADERS} ${HEADERS_COMPONENTS} ${SOURCES} ${SOURCES_SYSTEMS}) +add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) -target_link_libraries(Economy PRIVATE EnTT::EnTT) +target_link_libraries(${PROJECT_NAME} PRIVATE EnTT::EnTT) -target_include_directories(Economy PUBLIC include/) +target_include_directories(${PROJECT_NAME} PUBLIC include/) if (CMAKE_VERSION VERSION_GREATER 3.12) - set_property(TARGET Economy PROPERTY CXX_STANDARD 20) + set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) endif() \ No newline at end of file diff --git a/ECSAPI/Economy/include/ee_economy/components/container.hpp b/ECSAPI/Economy/include/ee_economy/components/container.hpp index 845006c..f734244 100644 --- a/ECSAPI/Economy/include/ee_economy/components/container.hpp +++ b/ECSAPI/Economy/include/ee_economy/components/container.hpp @@ -4,7 +4,7 @@ namespace ee_economy { - struct container + struct Container { double capacity = 0.; double total = 0.; diff --git a/ECSAPI/Economy/include/ee_economy/components/deliverer.hpp b/ECSAPI/Economy/include/ee_economy/components/deliverer.hpp index 00a0790..825a022 100644 --- a/ECSAPI/Economy/include/ee_economy/components/deliverer.hpp +++ b/ECSAPI/Economy/include/ee_economy/components/deliverer.hpp @@ -4,7 +4,7 @@ namespace ee_economy { - struct deliver_contract + struct DeliverContract { entt::entity from; entt::entity to; @@ -15,10 +15,10 @@ namespace ee_economy double distance = 1.0; }; - struct deliverer + struct Deliverer { RESOURCE_TYPE resource = RESOURCE_TYPE::NONE; - std::vector contracts; + std::vector contracts; }; } \ No newline at end of file diff --git a/ECSAPI/Economy/include/ee_economy/components/enterprise.hpp b/ECSAPI/Economy/include/ee_economy/components/enterprise.hpp index a40b627..2addb79 100644 --- a/ECSAPI/Economy/include/ee_economy/components/enterprise.hpp +++ b/ECSAPI/Economy/include/ee_economy/components/enterprise.hpp @@ -5,9 +5,9 @@ namespace ee_economy { - struct enterprise + struct Enterprise { - bool is_building = false; + bool isBuilding = false; entt::entity state; ACTION_TYPE action = ACTION_TYPE::STORE; @@ -17,39 +17,39 @@ namespace ee_economy * Production - */ double efficiency = 0.; - double base_efficiency = 0.; - double factor_efficiency = 1.; + double baseEfficiency = 0.; + double factorEfficiency = 1.; - std::vector links_from; - std::vector links_to; + std::vector linksFrom; + std::vector linksTo; - uint16_t staff_size = 1; + uint16_t staffSize = 1; // This can be splitted in percents between bank enterprises in future - double total_money = 0; + double totalMoney = 0; double salary = 0; - bool is_bankrupt = false; + bool isBankrupt = false; - void set_money(double value) + void setMoney(double value) { - total_money = value; + totalMoney = value; } - inline void update_efficiency() + inline void updateEfficiency() { - this->efficiency = this->base_efficiency * this->factor_efficiency; + this->efficiency = this->baseEfficiency * this->factorEfficiency; } - void set_base_efficiency(double value) + void setBaseEfficiency(double value) { - this->base_efficiency = value; - update_efficiency(); + this->baseEfficiency = value; + updateEfficiency(); } - void set_factor_efficiency(double value) + void setFactorEfficiency(double value) { - this->factor_efficiency = value; - update_efficiency(); + this->factorEfficiency = value; + updateEfficiency(); } }; } \ No newline at end of file diff --git a/ECSAPI/Economy/include/ee_economy/components/miner.hpp b/ECSAPI/Economy/include/ee_economy/components/miner.hpp index 92e266f..44cb3c2 100644 --- a/ECSAPI/Economy/include/ee_economy/components/miner.hpp +++ b/ECSAPI/Economy/include/ee_economy/components/miner.hpp @@ -4,7 +4,7 @@ namespace ee_economy { - struct miner + struct Miner { RESOURCE_TYPE resource = RESOURCE_TYPE::NONE; }; diff --git a/ECSAPI/Economy/include/ee_economy/components/producer.hpp b/ECSAPI/Economy/include/ee_economy/components/producer.hpp index fc6d12a..379f2bc 100644 --- a/ECSAPI/Economy/include/ee_economy/components/producer.hpp +++ b/ECSAPI/Economy/include/ee_economy/components/producer.hpp @@ -2,7 +2,7 @@ namespace ee_economy { - struct producer + struct Producer { }; diff --git a/ECSAPI/Economy/include/ee_economy/components/state.hpp b/ECSAPI/Economy/include/ee_economy/components/state.hpp index 6ee9d23..0b5cb1a 100644 --- a/ECSAPI/Economy/include/ee_economy/components/state.hpp +++ b/ECSAPI/Economy/include/ee_economy/components/state.hpp @@ -3,7 +3,7 @@ namespace ee_economy { - struct state { - int16_t external_id = -1; + struct State { + int16_t externalId = -1; }; } \ No newline at end of file diff --git a/ECSAPI/Economy/include/ee_economy/enterprise_defaults.hpp b/ECSAPI/Economy/include/ee_economy/enterprise_defaults.hpp index 326b5fd..64e0164 100644 --- a/ECSAPI/Economy/include/ee_economy/enterprise_defaults.hpp +++ b/ECSAPI/Economy/include/ee_economy/enterprise_defaults.hpp @@ -4,12 +4,12 @@ namespace ee_economy { - struct enterprise_defaults + struct EnterpriseDefaults { - container container; + Container container; - RESOURCE_TYPE resource_target = RESOURCE_TYPE::NONE; - double base_efficiency = 0.0; - double factor_efficiency = 1.0; + RESOURCE_TYPE resourceTarget = RESOURCE_TYPE::NONE; + double baseEfficiency = 0.0; + double factorEfficiency = 1.0; }; } \ No newline at end of file diff --git a/ECSAPI/Economy/include/ee_economy/resources_exchange.hpp b/ECSAPI/Economy/include/ee_economy/resources_exchange.hpp index cad73c5..81ac8b0 100644 --- a/ECSAPI/Economy/include/ee_economy/resources_exchange.hpp +++ b/ECSAPI/Economy/include/ee_economy/resources_exchange.hpp @@ -6,18 +6,18 @@ namespace ee_economy { - struct exchange_rule + struct ExchangeRule { - double out_value; + double outValue; std::unordered_map consume; }; - const std::unordered_map resources_exchange = { + const std::unordered_map resourcesExchange = { { RESOURCE_TYPE::FABRIC, exchange_rule { - .out_value = 2., + .outValue = 2., .consume = { {RESOURCE_TYPE::WOOL, 3.} } diff --git a/ECSAPI/Economy/include/ee_economy/systems.hpp b/ECSAPI/Economy/include/ee_economy/systems.hpp index 2cb7317..f13bb5e 100644 --- a/ECSAPI/Economy/include/ee_economy/systems.hpp +++ b/ECSAPI/Economy/include/ee_economy/systems.hpp @@ -3,7 +3,7 @@ namespace ee_economy { - void enterprise_routine(entt::registry& registry); + void enterpriseRoutine(entt::registry& registry); void mining(entt::registry& registry); // void producing(entt::registry& registry); diff --git a/ECSAPI/Economy/src/systems/delivering.cpp b/ECSAPI/Economy/src/systems/delivering.cpp index 5c75c67..0f53bd6 100644 --- a/ECSAPI/Economy/src/systems/delivering.cpp +++ b/ECSAPI/Economy/src/systems/delivering.cpp @@ -2,54 +2,54 @@ void ee_economy::delivering(entt::registry ®istry) { - auto deliverers = registry.view(); + auto deliverers = registry.view(); for (auto [entity, enterprise, deliverer, storage]: deliverers.each()) { - if (enterprise.is_bankrupt) continue; + if (enterprise.isBankrupt) continue; - for (deliver_contract &contract: deliverer.contracts) + for (DeliverContract &contract: deliverer.contracts) { - double paid_amount = contract.amount; + double paidAmount = contract.amount; if (contract.cost > 0) { - ee_economy::enterprise &sponsor = registry.get(contract.sponsor); + Enterprise &sponsor = registry.get(contract.sponsor); - double cost_per_one = contract.cost / contract.amount; + double costPerOne = contract.cost / contract.amount; double payment = contract.cost; - if (payment > sponsor.total_money) + if (payment > sponsor.totalMoney) { - payment = (int)(sponsor.total_money / cost_per_one) * cost_per_one; - paid_amount = payment / cost_per_one; + payment = (int)(sponsor.totalMoney / costPerOne) * costPerOne; + paidAmount = payment / costPerOne; } - sponsor.set_money(sponsor.total_money - payment); - enterprise.set_money(enterprise.total_money + payment); + sponsor.setMoney(sponsor.totalMoney - payment); + enterprise.setMoney(enterprise.totalMoney + payment); contract.cost -= payment; } - container &from_storage = registry.get(contract.from); - container &to_storage = registry.get(contract.to); + Container &fromStorage = registry.get(contract.from); + Container &toStorage = registry.get(contract.to); - double deliver_value = enterprise.efficiency; + double deliverValue = enterprise.efficiency; if (contract.amount < enterprise.efficiency) - deliver_value = contract.amount; - if (to_storage.total + deliver_value > to_storage.capacity) - deliver_value = to_storage.capacity - to_storage.total; - if (deliver_value > from_storage.content[deliverer.resource]) - deliver_value = from_storage.content[deliverer.resource]; - if (deliver_value > paid_amount) - deliver_value = paid_amount; - if (deliver_value < 0.0) - deliver_value = 0.0; + deliverValue = contract.amount; + if (toStorage.total + deliverValue > toStorage.capacity) + deliverValue = toStorage.capacity - toStorage.total; + if (deliverValue > fromStorage.content[deliverer.resource]) + deliverValue = fromStorage.content[deliverer.resource]; + if (deliverValue > paidAmount) + deliverValue = paidAmount; + if (deliverValue < 0.0) + deliverValue = 0.0; - to_storage.add(deliverer.resource, deliver_value); - from_storage.add(deliverer.resource, -deliver_value); - contract.amount -= deliver_value; + toStorage.add(deliverer.resource, deliverValue); + fromStorage.add(deliverer.resource, -deliverValue); + contract.amount -= deliverValue; } - std::erase_if(deliverer.contracts, [](const deliver_contract &contract) { + std::erase_if(deliverer.contracts, [](const DeliverContract &contract) { return contract.amount <= 0.0; }); } diff --git a/ECSAPI/Economy/src/systems/enterprise_routine.cpp b/ECSAPI/Economy/src/systems/enterprise_routine.cpp index 933b0fe..c038252 100644 --- a/ECSAPI/Economy/src/systems/enterprise_routine.cpp +++ b/ECSAPI/Economy/src/systems/enterprise_routine.cpp @@ -1,20 +1,20 @@ #include -void ee_economy::enterprise_routine(entt::registry ®istry) +void ee_economy::enterpriseRoutine(entt::registry ®istry) { - auto enterprises = registry.view(); + auto enterprises = registry.view(); for (auto [entity, enterprise]: enterprises.each()) { - double salary_debt = enterprise.salary * enterprise.staff_size; - if (enterprise.total_money < salary_debt) + double salaryDebt = enterprise.salary * enterprise.staffSize; + if (enterprise.totalMoney < salaryDebt) { - enterprise.is_bankrupt = true; - enterprise.set_money(0.0); + enterprise.isBankrupt = true; + enterprise.setMoney(0.0); } else { - enterprise.set_money(enterprise.total_money - salary_debt); + enterprise.setMoney(enterprise.totalMoney - salaryDebt); } } } \ No newline at end of file diff --git a/ECSAPI/Economy/src/systems/mining.cpp b/ECSAPI/Economy/src/systems/mining.cpp index 68fda17..323717c 100644 --- a/ECSAPI/Economy/src/systems/mining.cpp +++ b/ECSAPI/Economy/src/systems/mining.cpp @@ -2,21 +2,21 @@ void ee_economy::mining(entt::registry ®istry) { - auto miners = registry.view(); + auto miners = registry.view(); - for (auto [entity, enterprise, miner, local_storage]: miners.each()) + for (auto [entity, enterprise, miner, localStorage]: miners.each()) { - if (enterprise.is_bankrupt) continue; + if (enterprise.isBankrupt) continue; - container& state = registry.get(enterprise.state); + Container& state = registry.get(enterprise.state); - double mined_value = enterprise.efficiency; - if (local_storage.total + mined_value > local_storage.capacity) - mined_value = local_storage.capacity - local_storage.total; - if (mined_value > state.content[miner.resource]) - mined_value = state.content[miner.resource]; + double minedValue = enterprise.efficiency; + if (localStorage.total + minedValue > localStorage.capacity) + minedValue = localStorage.capacity - localStorage.total; + if (minedValue > state.content[miner.resource]) + minedValue = state.content[miner.resource]; - local_storage.add(miner.resource, mined_value); - state.add(miner.resource, -mined_value); + localStorage.add(miner.resource, minedValue); + state.add(miner.resource, -minedValue); } } \ No newline at end of file diff --git a/ECSAPI/Economy/test/CMakeLists.txt b/ECSAPI/Economy/test/CMakeLists.txt index 306f0a4..36a932f 100644 --- a/ECSAPI/Economy/test/CMakeLists.txt +++ b/ECSAPI/Economy/test/CMakeLists.txt @@ -1,3 +1,5 @@ +project(economy_tests) + # List sources set(SOURCES "test_conf.hpp" "main.cpp" @@ -11,14 +13,14 @@ find_package(GTest CONFIG REQUIRED) include(GoogleTest) -add_executable(economy_tests ${SOURCES}) -target_link_libraries(economy_tests PRIVATE GTest::gtest_main) -target_link_libraries(economy_tests PRIVATE Economy::Economy) +add_executable(${PROJECT_NAME} ${SOURCES}) +target_link_libraries(${PROJECT_NAME} PRIVATE GTest::gtest_main) +target_link_libraries(${PROJECT_NAME} PRIVATE Economy::Economy) # Test if (CMAKE_VERSION VERSION_GREATER 3.12) - set_property(TARGET economy_tests PROPERTY CXX_STANDARD 20) + set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) endif() -gtest_discover_tests(economy_tests) \ No newline at end of file +gtest_discover_tests(${PROJECT_NAME}) \ No newline at end of file diff --git a/ECSAPI/Economy/test/systems/delivering.cpp b/ECSAPI/Economy/test/systems/delivering.cpp index 718457e..e1dd1c1 100644 --- a/ECSAPI/Economy/test/systems/delivering.cpp +++ b/ECSAPI/Economy/test/systems/delivering.cpp @@ -6,140 +6,140 @@ TEST_F(SystemsTest, DeliverySingleNormal) { // [Miner -> Storage] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_enterprise.set_base_efficiency(1.0); - deliverer_deliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererEnterprise.setBaseEfficiency(1.0); + delivererDeliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); - ee_economy::container &from_container = registry.get(miner); - ee_economy::container &to_container = registry.get(storage); + ee_economy::Container &fromContainer = registry.get(miner); + ee_economy::Container &toContainer = registry.get(storage); - from_container.capacity = 15.0; - from_container.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); + fromContainer.capacity = 15.0; + fromContainer.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); - to_container.capacity = 15.0; + toContainer.capacity = 15.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(from_container.total, 14.0); - ASSERT_DOUBLE_EQ(from_container.content[ee_economy::RESOURCE_TYPE::COAL], 14.0); - ASSERT_DOUBLE_EQ(to_container.total, 1.0); - ASSERT_DOUBLE_EQ(to_container.content[ee_economy::RESOURCE_TYPE::COAL], 1.0); - ASSERT_EQ(deliverer_deliverer.contracts.size(), 1); + ASSERT_DOUBLE_EQ(fromContainer.total, 14.0); + ASSERT_DOUBLE_EQ(fromContainer.content[ee_economy::RESOURCE_TYPE::COAL], 14.0); + ASSERT_DOUBLE_EQ(toContainer.total, 1.0); + ASSERT_DOUBLE_EQ(toContainer.content[ee_economy::RESOURCE_TYPE::COAL], 1.0); + ASSERT_EQ(delivererDeliverer.contracts.size(), 1); } TEST_F(SystemsTest, DeliverySingleEmpty) { // [Miner -> Storage] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_enterprise.set_base_efficiency(1.0); - deliverer_deliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererEnterprise.setBaseEfficiency(1.0); + delivererDeliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); - ee_economy::container &from_container = registry.get(miner); - ee_economy::container &to_container = registry.get(storage); + ee_economy::Container &fromContainer = registry.get(miner); + ee_economy::Container &toContainer = registry.get(storage); - from_container.capacity = 15.0; - to_container.capacity = 15.0; + fromContainer.capacity = 15.0; + toContainer.capacity = 15.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(from_container.total, 0.0); - ASSERT_DOUBLE_EQ(from_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); - ASSERT_DOUBLE_EQ(to_container.total, 0.0); - ASSERT_DOUBLE_EQ(to_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); - ASSERT_EQ(deliverer_deliverer.contracts.size(), 1); + ASSERT_DOUBLE_EQ(fromContainer.total, 0.0); + ASSERT_DOUBLE_EQ(fromContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_DOUBLE_EQ(toContainer.total, 0.0); + ASSERT_DOUBLE_EQ(toContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_EQ(delivererDeliverer.contracts.size(), 1); } TEST_F(SystemsTest, DeliverySinglePoor) { // [Miner -> Storage] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_enterprise.set_base_efficiency(1.0); - deliverer_deliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererEnterprise.setBaseEfficiency(1.0); + delivererDeliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); - ee_economy::container &from_container = registry.get(miner); - ee_economy::container &to_container = registry.get(storage); + ee_economy::Container &fromContainer = registry.get(miner); + ee_economy::Container &toContainer = registry.get(storage); - from_container.capacity = 15.0; - from_container.add(ee_economy::RESOURCE_TYPE::COAL, 0.5); + fromContainer.capacity = 15.0; + fromContainer.add(ee_economy::RESOURCE_TYPE::COAL, 0.5); - to_container.capacity = 15.0; + toContainer.capacity = 15.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(from_container.total, 0.0); - ASSERT_DOUBLE_EQ(from_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); - ASSERT_DOUBLE_EQ(to_container.total, 0.5); - ASSERT_DOUBLE_EQ(to_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.5); - ASSERT_EQ(deliverer_deliverer.contracts.size(), 1); + ASSERT_DOUBLE_EQ(fromContainer.total, 0.0); + ASSERT_DOUBLE_EQ(fromContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_DOUBLE_EQ(toContainer.total, 0.5); + ASSERT_DOUBLE_EQ(toContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.5); + ASSERT_EQ(delivererDeliverer.contracts.size(), 1); } TEST_F(SystemsTest, DeliverySingleFinishContract) { // [Miner -> Storage] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_enterprise.set_base_efficiency(15.0); - deliverer_deliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererEnterprise.setBaseEfficiency(15.0); + delivererDeliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); - ee_economy::container &from_container = registry.get(miner); - ee_economy::container &to_container = registry.get(storage); + ee_economy::Container &fromContainer = registry.get(miner); + ee_economy::Container &toContainer = registry.get(storage); - from_container.capacity = 15.0; - from_container.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); + fromContainer.capacity = 15.0; + fromContainer.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); - to_container.capacity = 15.0; + toContainer.capacity = 15.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(from_container.total, 5.0); - ASSERT_DOUBLE_EQ(from_container.content[ee_economy::RESOURCE_TYPE::COAL], 5.0); - ASSERT_DOUBLE_EQ(to_container.total, 10.0); - ASSERT_DOUBLE_EQ(to_container.content[ee_economy::RESOURCE_TYPE::COAL], 10.0); - ASSERT_EQ(deliverer_deliverer.contracts.size(), 0); + ASSERT_DOUBLE_EQ(fromContainer.total, 5.0); + ASSERT_DOUBLE_EQ(fromContainer.content[ee_economy::RESOURCE_TYPE::COAL], 5.0); + ASSERT_DOUBLE_EQ(toContainer.total, 10.0); + ASSERT_DOUBLE_EQ(toContainer.content[ee_economy::RESOURCE_TYPE::COAL], 10.0); + ASSERT_EQ(delivererDeliverer.contracts.size(), 0); } TEST_F(SystemsTest, DeliveryMultipleFinishPoorCycle) { // [Miner -> Storage | Storage -> Miner] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_enterprise.set_base_efficiency(16.0); - deliverer_deliverer.contracts.push_back({.from = miner, .to = storage, .amount = 20.0}); - deliverer_deliverer.contracts.push_back({.from = storage, .to = miner, .amount = 5.0}); + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererEnterprise.setBaseEfficiency(16.0); + delivererDeliverer.contracts.push_back({.from = miner, .to = storage, .amount = 20.0}); + delivererDeliverer.contracts.push_back({.from = storage, .to = miner, .amount = 5.0}); - ee_economy::container &miner_container = registry.get(miner); - ee_economy::container &storage_container = registry.get(storage); + ee_economy::Container &minerContainer = registry.get(miner); + ee_economy::Container &storageContainer = registry.get(storage); - miner_container.capacity = 15.0; - miner_container.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); + minerContainer.capacity = 15.0; + minerContainer.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); - storage_container.capacity = 15.0; + storageContainer.capacity = 15.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(miner_container.total, 5.0); - ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 5.0); - ASSERT_DOUBLE_EQ(storage_container.total, 10.0); - ASSERT_DOUBLE_EQ(storage_container.content[ee_economy::RESOURCE_TYPE::COAL], 10.0); - ASSERT_EQ(deliverer_deliverer.contracts.size(), 1); - ASSERT_EQ(deliverer_deliverer.contracts[0].from, miner); + ASSERT_DOUBLE_EQ(minerContainer.total, 5.0); + ASSERT_DOUBLE_EQ(minerContainer.content[ee_economy::RESOURCE_TYPE::COAL], 5.0); + ASSERT_DOUBLE_EQ(storageContainer.total, 10.0); + ASSERT_DOUBLE_EQ(storageContainer.content[ee_economy::RESOURCE_TYPE::COAL], 10.0); + ASSERT_EQ(delivererDeliverer.contracts.size(), 1); + ASSERT_EQ(delivererDeliverer.contracts[0].from, miner); } TEST_F(SystemsTest, DeliveryPayment) @@ -147,12 +147,12 @@ TEST_F(SystemsTest, DeliveryPayment) // [Miner -> Storage] by Deliverer for $Miner // [Miner -> Storage] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_enterprise.set_base_efficiency(10.0); - deliverer_deliverer.contracts.push_back({ + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererEnterprise.setBaseEfficiency(10.0); + delivererDeliverer.contracts.push_back({ .from = miner, .to = storage, .sponsor = miner, @@ -160,26 +160,26 @@ TEST_F(SystemsTest, DeliveryPayment) .cost = 100.0 }); - ee_economy::container &from_container = registry.get(miner); - ee_economy::enterprise &from_enterprise = registry.get(miner); - ee_economy::container &to_container = registry.get(storage); + ee_economy::Container &fromContainer = registry.get(miner); + ee_economy::Enterprise &fromEnterprise = registry.get(miner); + ee_economy::Container &toContainer = registry.get(storage); - from_container.capacity = 10.0; - from_container.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); - from_enterprise.set_money(95.0); + fromContainer.capacity = 10.0; + fromContainer.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); + fromEnterprise.setMoney(95.0); - to_container.capacity = 10.0; + toContainer.capacity = 10.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(from_container.total, 1.0); - ASSERT_DOUBLE_EQ(from_container.content[ee_economy::RESOURCE_TYPE::COAL], 1.0); - ASSERT_DOUBLE_EQ(to_container.total, 9.0); - ASSERT_DOUBLE_EQ(to_container.content[ee_economy::RESOURCE_TYPE::COAL], 9.0); - ASSERT_DOUBLE_EQ(from_enterprise.total_money, 5.0); - ASSERT_DOUBLE_EQ(deliverer_enterprise.total_money, 90.0); + ASSERT_DOUBLE_EQ(fromContainer.total, 1.0); + ASSERT_DOUBLE_EQ(fromContainer.content[ee_economy::RESOURCE_TYPE::COAL], 1.0); + ASSERT_DOUBLE_EQ(toContainer.total, 9.0); + ASSERT_DOUBLE_EQ(toContainer.content[ee_economy::RESOURCE_TYPE::COAL], 9.0); + ASSERT_DOUBLE_EQ(fromEnterprise.totalMoney, 5.0); + ASSERT_DOUBLE_EQ(delivererEnterprise.totalMoney, 90.0); - ee_economy::deliver_contract contract = deliverer_deliverer.contracts[0]; + ee_economy::DeliverContract contract = delivererDeliverer.contracts[0]; ASSERT_DOUBLE_EQ(contract.cost, 10.0); ASSERT_DOUBLE_EQ(contract.amount, 1.0); } @@ -188,27 +188,27 @@ TEST_F(SystemsTest, DeliveryBankrupt) { // [Miner -> Storage] by Deliverer - ee_economy::enterprise &deliverer_enterprise = registry.get(deliverer); - ee_economy::deliverer &deliverer_deliverer = registry.get(deliverer); + ee_economy::Enterprise &delivererEnterprise = registry.get(deliverer); + ee_economy::Deliverer &delivererDeliverer = registry.get(deliverer); - deliverer_deliverer.resource = ee_economy::RESOURCE_TYPE::COAL; - deliverer_deliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); - deliverer_enterprise.set_base_efficiency(1.0); - deliverer_enterprise.is_bankrupt = true; + delivererDeliverer.resource = ee_economy::RESOURCE_TYPE::COAL; + delivererDeliverer.contracts.push_back({.from = miner, .to = storage, .amount = 10.0}); + delivererEnterprise.setBaseEfficiency(1.0); + delivererEnterprise.isBankrupt = true; - ee_economy::container &from_container = registry.get(miner); - ee_economy::container &to_container = registry.get(storage); + ee_economy::Container &fromContainer = registry.get(miner); + ee_economy::Container &toContainer = registry.get(storage); - from_container.capacity = 15.0; - from_container.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); + fromContainer.capacity = 15.0; + fromContainer.add(ee_economy::RESOURCE_TYPE::COAL, 15.0); - to_container.capacity = 15.0; + toContainer.capacity = 15.0; ee_economy::delivering(registry); - ASSERT_DOUBLE_EQ(from_container.total, 15.0); - ASSERT_DOUBLE_EQ(from_container.content[ee_economy::RESOURCE_TYPE::COAL], 15.0); - ASSERT_DOUBLE_EQ(to_container.total, 0.0); - ASSERT_DOUBLE_EQ(to_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); - ASSERT_EQ(deliverer_deliverer.contracts.size(), 1); + ASSERT_DOUBLE_EQ(fromContainer.total, 15.0); + ASSERT_DOUBLE_EQ(fromContainer.content[ee_economy::RESOURCE_TYPE::COAL], 15.0); + ASSERT_DOUBLE_EQ(toContainer.total, 0.0); + ASSERT_DOUBLE_EQ(toContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_EQ(delivererDeliverer.contracts.size(), 1); } \ No newline at end of file diff --git a/ECSAPI/Economy/test/systems/enterprise_routine.cpp b/ECSAPI/Economy/test/systems/enterprise_routine.cpp index 086fe21..4f814b2 100644 --- a/ECSAPI/Economy/test/systems/enterprise_routine.cpp +++ b/ECSAPI/Economy/test/systems/enterprise_routine.cpp @@ -4,26 +4,26 @@ TEST_F(SystemsTest, RoutineNormal) { - ee_economy::enterprise &miner_enterprise = registry.get(miner); - miner_enterprise.set_money(1000000000.0); - miner_enterprise.salary = 100000.0; - miner_enterprise.staff_size = 10; + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + minerEnterprise.setMoney(1000000000.0); + minerEnterprise.salary = 100000.0; + minerEnterprise.staffSize = 10; - ee_economy::enterprise_routine(registry); + ee_economy::enterpriseRoutine(registry); - ASSERT_DOUBLE_EQ(miner_enterprise.total_money, 999000000.0); - ASSERT_FALSE(miner_enterprise.is_bankrupt); + ASSERT_DOUBLE_EQ(minerEnterprise.totalMoney, 999000000.0); + ASSERT_FALSE(minerEnterprise.isBankrupt); } TEST_F(SystemsTest, RoutineBankruptcy) { - ee_economy::enterprise &miner_enterprise = registry.get(miner); - miner_enterprise.set_money(1000000.0); - miner_enterprise.salary = 100000.0; - miner_enterprise.staff_size = 11; + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + minerEnterprise.setMoney(1000000.0); + minerEnterprise.salary = 100000.0; + minerEnterprise.staffSize = 11; - ee_economy::enterprise_routine(registry); + ee_economy::enterpriseRoutine(registry); - ASSERT_DOUBLE_EQ(miner_enterprise.total_money, 0.0); - ASSERT_TRUE(miner_enterprise.is_bankrupt); + ASSERT_DOUBLE_EQ(minerEnterprise.totalMoney, 0.0); + ASSERT_TRUE(minerEnterprise.isBankrupt); } \ No newline at end of file diff --git a/ECSAPI/Economy/test/systems/mining.cpp b/ECSAPI/Economy/test/systems/mining.cpp index 7b52ecb..e92ba28 100644 --- a/ECSAPI/Economy/test/systems/mining.cpp +++ b/ECSAPI/Economy/test/systems/mining.cpp @@ -4,110 +4,110 @@ TEST_F(SystemsTest, MiningNormal) { - ee_economy::container &state_container = registry.get(state); - ee_economy::container &miner_container = registry.get(miner); - ee_economy::enterprise &miner_enterprise = registry.get(miner); - ee_economy::miner &miner_miner = registry.get(miner); + ee_economy::Container &stateContainer = registry.get(state); + ee_economy::Container &minerContainer = registry.get(miner); + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + ee_economy::Miner &minerMiner = registry.get(miner); - state_container.capacity = 15.0; - state_container.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); + stateContainer.capacity = 15.0; + stateContainer.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); - miner_container.capacity = 5.0; - miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL; - miner_enterprise.set_base_efficiency(0.1); + minerContainer.capacity = 5.0; + minerMiner.resource = ee_economy::RESOURCE_TYPE::COAL; + minerEnterprise.setBaseEfficiency(0.1); ee_economy::mining(registry); - ASSERT_DOUBLE_EQ(state_container.total, 9.9); - ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 9.9); - ASSERT_DOUBLE_EQ(miner_container.total, 0.1); - ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.1); + ASSERT_DOUBLE_EQ(stateContainer.total, 9.9); + ASSERT_DOUBLE_EQ(stateContainer.content[ee_economy::RESOURCE_TYPE::COAL], 9.9); + ASSERT_DOUBLE_EQ(minerContainer.total, 0.1); + ASSERT_DOUBLE_EQ(minerContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.1); } TEST_F(SystemsTest, MiningEmptyState) { - ee_economy::container &state_container = registry.get(state); - ee_economy::container &miner_container = registry.get(miner); - ee_economy::enterprise &miner_enterprise = registry.get(miner); - ee_economy::miner &miner_miner = registry.get(miner); + ee_economy::Container &stateContainer = registry.get(state); + ee_economy::Container &minerContainer = registry.get(miner); + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + ee_economy::Miner &minerMiner = registry.get(miner); - state_container.capacity = 15.0; + stateContainer.capacity = 15.0; - miner_container.capacity = 5.0; - miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL; - miner_enterprise.set_base_efficiency(0.1); + minerContainer.capacity = 5.0; + minerMiner.resource = ee_economy::RESOURCE_TYPE::COAL; + minerEnterprise.setBaseEfficiency(0.1); ee_economy::mining(registry); - ASSERT_DOUBLE_EQ(state_container.total, 0.0); - ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); - ASSERT_DOUBLE_EQ(miner_container.total, 0.0); - ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_DOUBLE_EQ(stateContainer.total, 0.0); + ASSERT_DOUBLE_EQ(stateContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_DOUBLE_EQ(minerContainer.total, 0.0); + ASSERT_DOUBLE_EQ(minerContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); } TEST_F(SystemsTest, MiningPoorState) { - ee_economy::container &state_container = registry.get(state); - ee_economy::container &miner_container = registry.get(miner); - ee_economy::enterprise &miner_enterprise = registry.get(miner); - ee_economy::miner &miner_miner = registry.get(miner); + ee_economy::Container &stateContainer = registry.get(state); + ee_economy::Container &minerContainer = registry.get(miner); + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + ee_economy::Miner &minerMiner = registry.get(miner); - state_container.capacity = 15.0; - state_container.add(ee_economy::RESOURCE_TYPE::COAL, 0.05); + stateContainer.capacity = 15.0; + stateContainer.add(ee_economy::RESOURCE_TYPE::COAL, 0.05); - miner_container.capacity = 5.0; - miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL; - miner_enterprise.set_base_efficiency(0.1); + minerContainer.capacity = 5.0; + minerMiner.resource = ee_economy::RESOURCE_TYPE::COAL; + minerEnterprise.setBaseEfficiency(0.1); ee_economy::mining(registry); - ASSERT_DOUBLE_EQ(state_container.total, 0.0); - ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); - ASSERT_DOUBLE_EQ(miner_container.total, 0.05); - ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.05); + ASSERT_DOUBLE_EQ(stateContainer.total, 0.0); + ASSERT_DOUBLE_EQ(stateContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_DOUBLE_EQ(minerContainer.total, 0.05); + ASSERT_DOUBLE_EQ(minerContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.05); } TEST_F(SystemsTest, MiningReachCap) { - ee_economy::container &state_container = registry.get(state); - ee_economy::container &miner_container = registry.get(miner); - ee_economy::enterprise &miner_enterprise = registry.get(miner); - ee_economy::miner &miner_miner = registry.get(miner); + ee_economy::Container &stateContainer = registry.get(state); + ee_economy::Container &minerContainer = registry.get(miner); + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + ee_economy::Miner &minerMiner = registry.get(miner); - state_container.capacity = 15.0; - state_container.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); + stateContainer.capacity = 15.0; + stateContainer.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); - miner_container.capacity = 0.05; - miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL; - miner_enterprise.set_base_efficiency(0.1); + minerContainer.capacity = 0.05; + minerMiner.resource = ee_economy::RESOURCE_TYPE::COAL; + minerEnterprise.setBaseEfficiency(0.1); ee_economy::mining(registry); - ASSERT_DOUBLE_EQ(state_container.total, 9.95); - ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 9.95); - ASSERT_DOUBLE_EQ(miner_container.total, 0.05); - ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.05); + ASSERT_DOUBLE_EQ(stateContainer.total, 9.95); + ASSERT_DOUBLE_EQ(stateContainer.content[ee_economy::RESOURCE_TYPE::COAL], 9.95); + ASSERT_DOUBLE_EQ(minerContainer.total, 0.05); + ASSERT_DOUBLE_EQ(minerContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.05); } TEST_F(SystemsTest, MiningBankrupt) { - ee_economy::container &state_container = registry.get(state); - ee_economy::container &miner_container = registry.get(miner); - ee_economy::enterprise &miner_enterprise = registry.get(miner); - ee_economy::miner &miner_miner = registry.get(miner); + ee_economy::Container &stateContainer = registry.get(state); + ee_economy::Container &minerContainer = registry.get(miner); + ee_economy::Enterprise &minerEnterprise = registry.get(miner); + ee_economy::Miner &minerMiner = registry.get(miner); - state_container.capacity = 15.0; - state_container.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); + stateContainer.capacity = 15.0; + stateContainer.add(ee_economy::RESOURCE_TYPE::COAL, 10.0); - miner_container.capacity = 5.0; - miner_miner.resource = ee_economy::RESOURCE_TYPE::COAL; - miner_enterprise.set_base_efficiency(0.1); - miner_enterprise.is_bankrupt = true; + minerContainer.capacity = 5.0; + minerMiner.resource = ee_economy::RESOURCE_TYPE::COAL; + minerEnterprise.setBaseEfficiency(0.1); + minerEnterprise.isBankrupt = true; ee_economy::mining(registry); - ASSERT_DOUBLE_EQ(state_container.total, 10.0); - ASSERT_DOUBLE_EQ(state_container.content[ee_economy::RESOURCE_TYPE::COAL], 10.0); - ASSERT_DOUBLE_EQ(miner_container.total, 0.0); - ASSERT_DOUBLE_EQ(miner_container.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); + ASSERT_DOUBLE_EQ(stateContainer.total, 10.0); + ASSERT_DOUBLE_EQ(stateContainer.content[ee_economy::RESOURCE_TYPE::COAL], 10.0); + ASSERT_DOUBLE_EQ(minerContainer.total, 0.0); + ASSERT_DOUBLE_EQ(minerContainer.content[ee_economy::RESOURCE_TYPE::COAL], 0.0); } \ No newline at end of file diff --git a/ECSAPI/Economy/test/test_conf.hpp b/ECSAPI/Economy/test/test_conf.hpp index 33e172f..7673dc7 100644 --- a/ECSAPI/Economy/test/test_conf.hpp +++ b/ECSAPI/Economy/test/test_conf.hpp @@ -18,25 +18,25 @@ struct SystemsTest : testing::Test { // Create state state = registry.create(); - registry.emplace(state); - registry.emplace(state); + registry.emplace(state); + registry.emplace(state); // Create miner enterprise miner = registry.create(); - registry.emplace(miner, false, state); - registry.emplace(miner); - registry.emplace(miner); + registry.emplace(miner, false, state); + registry.emplace(miner); + registry.emplace(miner); // Create storage enterprise storage = registry.create(); - registry.emplace(storage, false, state); - registry.emplace(storage); + registry.emplace(storage, false, state); + registry.emplace(storage); // Create delivering enterprise deliverer = registry.create(); - registry.emplace(deliverer, false, state); - registry.emplace(deliverer); - registry.emplace(deliverer); + registry.emplace(deliverer, false, state); + registry.emplace(deliverer); + registry.emplace(deliverer); } void TearDown() diff --git a/ECSAPI/vcpkg.json b/ECSAPI/vcpkg.json deleted file mode 100644 index efd46db..0000000 --- a/ECSAPI/vcpkg.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "dependencies": [ - "entt", - "gtest" - ] -} diff --git a/frontend/.vscode/launch.json b/frontend/.vscode/launch.json new file mode 100644 index 0000000..e8338f2 --- /dev/null +++ b/frontend/.vscode/launch.json @@ -0,0 +1,12 @@ +{ + "configurations": [ + { + "type": "cmake", + "request": "launch", + "name": "Debug portfile(s)", + "cmakeDebugType": "external", + "pipeName": "\\\\.\\pipe\\vcpkg_ext_portfile_dbg", + "preLaunchTask": "Debug vcpkg commands" + } + ] +} \ No newline at end of file diff --git a/frontend/CMakeLists.txt b/frontend/CMakeLists.txt new file mode 100644 index 0000000..bf4a0f5 --- /dev/null +++ b/frontend/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required (VERSION 3.8) + +if (POLICY CMP0141) + cmake_policy(SET CMP0141 NEW) + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") +endif() + +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +project (EEfrontend) + + +# List sources + +#set(HEADERS "RmlVulkanInterface.hpp") +set(SOURCES "main.cpp") + +#list(TRANSFORM HEADERS PREPEND "include/") +list(TRANSFORM SOURCES PREPEND "src/") + +# Find dependencies + +find_package(SDL2 CONFIG REQUIRED) +find_package(Vulkan REQUIRED) +find_package(RmlUi CONFIG REQUIRED) + +# Link library + +add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES}) + +target_link_libraries(${PROJECT_NAME} PRIVATE p7) +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + $ + $,SDL2::SDL2,SDL2::SDL2-static> +) +target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan) + +set(RMLUI_BACKEND_PATH ${RmlUi_SOURCE_DIR}/Backends) # Link SDL Vulkan backend for RmlUi +add_library(rmlui_backend_SDL_VK INTERFACE) +target_sources(rmlui_backend_SDL_VK INTERFACE + ${RMLUI_BACKEND_PATH}/RmlUi_Platform_SDL.cpp + ${RMLUI_BACKEND_PATH}/RmlUi_Renderer_VK.cpp +) +target_include_directories(rmlui_backend_SDL_VK INTERFACE ${RMLUI_BACKEND_PATH}) +target_compile_definitions(rmlui_backend_SDL_VK INTERFACE + RMLUI_SDL_VERSION_MAJOR=2 + RMLUI_NUM_MSAA_SAMPLES=4 + RMLUI_VK_CUSTOM_LOADER= +) +target_link_libraries(${PROJECT_NAME} PRIVATE RmlUi::RmlUi) + +target_include_directories(${PROJECT_NAME} PUBLIC include/) + +if (CMAKE_VERSION VERSION_GREATER 3.12) + set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) +endif() \ No newline at end of file diff --git a/frontend/src/main.cpp b/frontend/src/main.cpp new file mode 100644 index 0000000..245bf92 --- /dev/null +++ b/frontend/src/main.cpp @@ -0,0 +1,120 @@ +#ifdef _DEBUG + #define P7_SINK L"/P7.Sink=Console" +#else + #define P7_SINK L"/P7.Sink=FileTxt" +#endif + +#include "P7_Client.h" +#include "P7_Trace.h" +#include +#include +#include +#include + +int SDL_main(int argc, char **argv) +{ + // Setup P7 logger + IP7_Client *p7client = P7_Create_Client(P7_SINK); + P7_Set_Crash_Handler(); + IP7_Trace *logger = P7_Create_Trace(p7client, L"TC 1"); + logger->Register_Thread(L"MainThread", 0); + + // Setup SDL + bool quit = false; + SDL_Event event; + + SDL_Init(SDL_INIT_VIDEO); + + SDL_Window *window = SDL_CreateWindow( + "Etredia Empires", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + 800, + 600, + SDL_WINDOW_VULKAN + ); + + if (!window) + { + quit = true; + LOG(logger, CRITICAL, "SDL Window fails: %hs", SDL_GetError()); + } + else LOG(logger, INFO, "SDL Window created"); + + // Setup Vulkan + VkInstance vulkan; + + uint32_t sdlExtensionsCount = 0; + if ( !SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionsCount, nullptr) ) + LOG(logger, CRITICAL, "Fail to get SDL Vulkan extensions number! %hs", SDL_GetError()); + + const char **sdlExtentions = new const char*[sdlExtensionsCount](); + + if ( !SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionsCount, sdlExtentions) ) + LOG(logger, CRITICAL, "Fail to load SDL Vulkan extentions! %hs", SDL_GetError()); + else LOG(logger, INFO, "Load %d SDL Vulkan extenstions", sdlExtensionsCount); + + VkInstanceCreateInfo vkCreateConfig = { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .enabledLayerCount = 0, + .enabledExtensionCount = sdlExtensionsCount, + .ppEnabledExtensionNames = sdlExtentions + }; + + VkResult vkCreateResult = vkCreateInstance(&vkCreateConfig, nullptr, &vulkan); + if (vkCreateResult != VK_SUCCESS) + LOG(logger, CRITICAL, "Vulkan is not instantiated! Code: %d", vkCreateResult); + else LOG(logger, INFO, "Vulkan is instantiated"); + + delete[] sdlExtentions; + + //Setup RmlUi + if (!Rml::Initialise()) + LOG(logger, CRITICAL, "RmlUi initialization failed!"); + else LOG(logger, INFO, "RmlUi initialized"); + + int32_t screenWidth, screenHeight; + SDL_GetWindowSize(window, &screenWidth, &screenHeight); + Rml::Context *uiContext = Rml::CreateContext("default", Rml::Vector2i(screenWidth, screenHeight)); + + // Process SDL events + while(!quit) + { + SDL_WaitEvent(&event); + + switch(event.type) + { + case SDL_QUIT: + { + quit = true; + break; + } + + case SDL_WINDOWEVENT: + { + switch (event.window.event) + { + case SDL_WINDOWEVENT_RESIZED: + { + uiContext->SetDimensions(Rml::Vector2i(event.window.data1, event.window.data2)); + break; + } + } + + break; + } + } + + } + + // Free memory + LOG(logger, INFO, "Exit..."); + Rml::Shutdown(); + vkDestroyInstance(vulkan, nullptr); + SDL_Quit(); + logger->Unregister_Thread(0); + logger->Release(); + p7client->Release(); + + return 0; +} \ No newline at end of file diff --git a/p7lib/CMakeLists.txt b/p7lib/CMakeLists.txt new file mode 100644 index 0000000..1ca182c --- /dev/null +++ b/p7lib/CMakeLists.txt @@ -0,0 +1,69 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +#project(p7lib) + +#>>Build options ********************************************************************** +option(P7_TESTS_BUILD "Build test" OFF) +set(P7_BUILD_SHARED OFF CACHE INTERNAL "Build shared library") +#< + #endif + #include + + //Text marco, allow to use wchar_t automatically + #define TM(i_pStr) L##i_pStr + + #define XCHAR wchar_t + typedef wchar_t tWCHAR; + + #define WND_HANDLE HWND + + #define SHARED_EXT L"dll" + + #define P7_EXPORT __declspec(dllexport) + + #define OS_PATH_SEPARATOR TM("\\") + +//////////////////////////////////////////////////////////////////////////////// +//LINUX specific definitions & types +#elif defined(__linux__) + #define UTF8_ENCODING + #define G_OS_LINUX + + //Text marco, allow to use char automatically + #define TM(i_pStr) i_pStr + + #define XCHAR char + typedef unsigned short tWCHAR; + #define WND_HANDLE void* + + #define SHARED_EXT "so" + + typedef struct _GUID + { + unsigned int Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[ 8 ]; + } GUID; + + #define __stdcall + #define __cdecl + + #ifndef __forceinline + #if defined(GTX64) || defined(__PIC__) + #define __forceinline + #else + #define __forceinline __attribute__((always_inline)) + #endif + #endif + + #define P7_EXPORT __attribute__ ((visibility ("default"))) + + #define OS_PATH_SEPARATOR TM("/") +#endif + +#ifdef _MSC_VER + #define PRAGMA_PACK_ENTER(x) __pragma(pack(push, x)) + #define PRAGMA_PACK_EXIT() __pragma(pack(pop)) + #define ATTR_PACK(x) + #define ATTR_ALIGN(x) + #define UNUSED_FUNC +#else + #define PRAGMA_PACK_ENTER(x) + #define PRAGMA_PACK_EXIT(x) + #define ATTR_PACK(x) __attribute__ ((aligned(x), packed)) + #define ATTR_ALIGN(x) __attribute__ ((aligned(x))) + #define UNUSED_FUNC __attribute__ ((unused)) +#endif + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#define UNUSED_ARG(x) (void)(x) + +#define STR_HELPER(x) #x +#define TOSTR(x) STR_HELPER(x) + +#define TMM(i_pStr) TM(i_pStr) + +typedef unsigned long long tUINT64; +typedef long long tINT64; +typedef unsigned int tUINT32; +typedef int tINT32; +typedef unsigned short tUINT16; +typedef short tINT16; +typedef unsigned char tUINT8; +typedef char tINT8; +typedef char tACHAR; +//platfrorm specific char, Windows - wchar_t, Linix - char, +//XCHAR defined in PTypes.hpp specific for each platform or project. +#define tXCHAR XCHAR +//typedef XCHAR tXCHAR; +typedef unsigned int tBOOL; +typedef double tDOUBLE; + + +#define GASSERT(cond) typedef int assert_type[(cond) ? 1 : -1] + +#endif //GTYPE_H diff --git a/p7lib/Headers/P7_Client.h b/p7lib/Headers/P7_Client.h new file mode 100644 index 0000000..967eeae --- /dev/null +++ b/p7lib/Headers/P7_Client.h @@ -0,0 +1,574 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide client functionality / +// / +// +-------------------+ / +// | Sink | / +// | * Network (Baical)| / +// | * FileBin | / +// | * FileTxt | / +// | * Console | / +// | * Syslog | / +// | * Auto | / +// | * Null | / +// +---------^---------+ / +// | / +// | / +// +---------+---------+ / +// | P7 Client | / +// | [ Channels ] | / +// | +-+ +-+ +--+ | / +// | |0| |1| ...|31| | / +// | +^+ +^+ +-^+ | / +// +---|---|-------|---+ / +// | | | / +// +-----+ | +----------+ / +// | | | / +// | | | / +// +---+---+ +---+--------+ +---+---+ / +// | Trace | | Telemetry | | Trace | / +// |Channel| | channel | ... |Channel| / +// +-------+ +------------+ +-------+ / +// / +//////////////////////////////////////////////////////////////////////////////// +// // +// Documentation is located in /Documentation/P7.pdf // +// // +//////////////////////////////////////////////////////////////////////////////// +#ifndef P7_CLIENT_H +#define P7_CLIENT_H + +#include "GTypes.h" +#include "P7_Version.h" + +#define CLIENT_DEFAULT_SHARED_NAME TM("P7.Client") + +//Values: P7 sink (logs, traces & telemetry destination) +//There are 3 possible values: +// * Baical - over network to Baical server directly +// * File - to file +// * Auto - to Baical if connection is established, otherwise to file +// N.B.: connection timeout is 250 ms. +// * Null - all data will be dropped +// Default value: Baical +#define CLIENT_COMMAND_LINE_SINK TM("/P7.Sink=") + +#define CLIENT_SINK_BAICAL TM("Baical") +#define CLIENT_SINK_FILE_BIN TM("FileBin") +#define CLIENT_SINK_FILE_BIN_LEGACY TM("File") +#define CLIENT_SINK_FILE_TXT TM("FileTxt") +#define CLIENT_SINK_CONSOLE TM("Console") +#define CLIENT_SINK_SYSLOG TM("Syslog") +#define CLIENT_SINK_AUTO TM("Auto") +#define CLIENT_SINK_NULL TM("Null") + + +//Values: P7 client name, max length is about 96 characters, by default it is +//name of the process. Useful in case when P7 is used from script language and +//name of host process isn't usable - for example Python.exe +#define CLIENT_COMMAND_LINE_NAME TM("/P7.Name=") + +//////////////////////////////////////////////////////////////////////////////// +// Sink=Baical arguments / +//////////////////////////////////////////////////////////////////////////////// +//Values: server address +//IPV4 address : XXX.XXX.XXX.XXX +//IPV6 address : ::1, etc. +//NetBios Name : any name +#define CLIENT_COMMAND_LINE_BAICAL_ADDRESS TM("/P7.Addr=") + +//Values: server specified port +//default: 9009 +#define CLIENT_COMMAND_LINE_BAICAL_PORT TM("/P7.Port=") + +//Values: size of the data packet +// Min: 512 +// Max: 65535 +// Recommended: your network MTU size +// default: 1472 +#define CLIENT_COMMAND_PACKET_BAICAL_SIZE TM("/P7.PSize=") + +//size of the transmission window in packets. Sometimes is useful to manage it +//if server aggressively loose incoming packets, this parameter is for precise +//tuning, in most of the cases stay untouched and protocol manage it +//Min = 1 +//max = ((pool size / packet size) / 2) +#define CLIENT_COMMAND_WINDOW_BAICAL_SIZE TM("/P7.Window=") + +//specifies exit timeout in seconds, used to deliver last data chunks to server +//max value is 15 seconds +#define CLIENT_COMMAND_LINE_BAICAL_EXIT_TIMEOUT TM("/P7.Eto=") + +//////////////////////////////////////////////////////////////////////////////// +// Sink=File arguments / +//////////////////////////////////////////////////////////////////////////////// +//Value: path to destination file +//default: /P7logs +#define CLIENT_COMMAND_LINE_DIR TM("/P7.Dir=") + +//Value: define rolling type +// Xmb - rolling every X megabytes, for example /P7.Roll=10mb +// Xhr - rolling every X hours, for example /P7.Roll=24hr, max = 1000hr +// HH:MMtm - rolling by time (00:00 -> 23:59), for example: +// * rolling at 12:00 -> P7.Roll=12:00tm +// * rolling at 12:00 and 00:00 -> P7.Roll=00:00,12:00tm +//default: rolling is off +#define CLIENT_COMMAND_LINE_FILE_ROLLING TM("/P7.Roll=") + +//Value: define maximum P7 logs files in destination folder /P7.Dir="MyDir" +//in case if count of files is larger than specified value - oldest files will +//be removed +//default : off (0) +//min : 1 +//max : 4096 +#define CLIENT_COMMAND_LINE_FILES_COUNT_MAX TM("/P7.Files=") + + +//Value: define maximum P7 logs files cumulative size in MB at destination +//folder /P7.Dir="MyDir" in case if size of files is larger than specified +//value - oldest files will be removed +//default : off (0) +//min : 1 +//max : 4294967296 +#define CLIENT_COMMAND_LINE_FILES_SIZE_MAX TM("/P7.FSize=") + + +//////////////////////////////////////////////////////////////////////////////// +// general settings / +//////////////////////////////////////////////////////////////////////////////// +//Values: +// 0 : Debug +// 1 : Info +// 2 : Warnings +// 3 : Errors +// 4 : Critical +// default: logging is off +#define CLIENT_COMMAND_LOG_VERBOSITY TM("/P7.Verb=") + +//Manage internal logging +//Values: +// 0 : Off +// 1 : On +//default: On(1) +#define CLIENT_COMMAND_LOG_ON TM("/P7.On=") + +//size of the internal buffers pool in kilobytes. Minimal 16(kb), max is not +//specified +//default value = 1mb +#define CLIENT_COMMAND_POOL_SIZE TM("/P7.Pool=") + + +//specify do we need to flush channels inside P7_Exceptional_Flush call +//Values: 1 = yes, 0 = no +//default value = 1 +#define CLIENT_COMMAND_FLUSH_CHANNELS TM("/P7.FlashChannels=") + + +//specifies log message format for such sinks like: FileTxt, Console, SysLog +//format example: +// /P7.Format="%cn #%ix [%tf] %lv Tr:#%ti:%tn CPU:%cc Md:%mn {%fs:%fl:%fn} %ms" + +#define CLIENT_COMMAND_FORMAT TM("/P7.Format=") + +#define CLIENT_FMT_CHANNEL TM("cn") + +#define CLIENT_FMT_MSG_ID TM("id") +#define CLIENT_FMT_MSG_INDEX TM("ix") + +#define CLIENT_FMT_TIME_FULL TM("tf") +#define CLIENT_FMT_TIME_MEDIUM TM("tm") +#define CLIENT_FMT_TIME_SHORT TM("ts") +#define CLIENT_FMT_TIME_DIFF TM("td") +#define CLIENT_FMT_TIME_COUNT TM("tc") + +#define CLIENT_FMT_LEVEL TM("lv") + +#define CLIENT_FMT_THREAD_ID TM("ti") +#define CLIENT_FMT_THREAD_NAME TM("tn") + +#define CLIENT_FMT_CPU_CORE TM("cc") + +#define CLIENT_FMT_MODULE_ID TM("mi") +#define CLIENT_FMT_MODULE_NAME TM("mn") + +#define CLIENT_FMT_FILE_FULL TM("ff") +#define CLIENT_FMT_FILE_SHORT TM("fs") +#define CLIENT_FMT_FILE_LINE TM("fl") +#define CLIENT_FMT_FUNCTION TM("fn") + +#define CLIENT_FMT_MSG TM("ms") + + +//Syslog facility digit https://tools.ietf.org/html/rfc3164#page-8 +#define CLIENT_COMMAND_SYSLOG_FACILITY TM("/P7.Facility=") + + +//Values: No values +#define CLIENT_COMMAND_LOG_HELP TM("/P7.Help") + + +//////////////////////////////////////////////////////////////////////////////// +// Trace settings / +//////////////////////////////////////////////////////////////////////////////// + +//Override verbosity for all trace streams and modules +//Values: +//0 = EP7TRACE_LEVEL_TRACE +//1 = EP7TRACE_LEVEL_DEBUG +//2 = EP7TRACE_LEVEL_INFO +//3 = EP7TRACE_LEVEL_WARNING +//4 = EP7TRACE_LEVEL_ERROR +//5 = EP7TRACE_LEVEL_CRITICAL +//Example: /P7.Trc.Verb=5 +#define CLIENT_COMMAND_TRACE_VERBOSITY TM("/P7.Trc.Verb=") + + +#define CLIENT_HELP_STRING\ + TM("P7 arguments:\n")\ + TM(" -General arguments: \n")\ + TM(" /P7.Sink - Select data flow direction, there are few values:\n")\ + TM(" * Baical - to Baical server over network(fast and efficient)\n")\ + TM(" * FileBin - to local binary file (fast and efficient)\n")\ + TM(" * FileTxt - to local text file (slow comparing to FileBin/Baical)\n")\ + TM(" * Syslog - to syslog server (slow comparing to FileBin/Baical)\n")\ + TM(" * Console - to console (slow comparing to FileBin/Baical)\n")\ + TM(" * Auto - to Baical server if connection is istablished, otherwise to file\n")\ + TM(" N.B.: connection timeout is 250 ms !\n")\ + TM(" * Null - drop all incoming data\n")\ + TM(" Examples:\n")\ + TM(" /P7.Sink=Baical\n")\ + TM(" /P7.Sink=File\n")\ + TM(" /P7.Sink=Null\n")\ + TM(" /P7.Name - P7 client name, max length is about 96 characters, by default it is\n")\ + TM(" name of the host process. Useful in case when P7 is used from scrip\n")\ + TM(" language and name of host process is not suitable - for example Python.exe\n")\ + TM(" Example:\n")\ + TM(" /P7.Name=Client\n")\ + TM(" /P7.On - Enable/Disable P7 network engine, By default P7 is on\n")\ + TM(" Examples:\n")\ + TM(" /P7.On=1\n")\ + TM(" /P7.On=0\n")\ + TM(" /P7.Verb - Set logging verbosity level. This option allow to write\n")\ + TM(" to text log file or stdout all internal engine messages.\n")\ + TM(" Do not specify /P7.Verb parameter to switch off the logging\n")\ + TM(" P7 internal logging has next verbosity levels:\n")\ + TM(" 0 : Info\n")\ + TM(" 1 : Debug\n")\ + TM(" 2 : Warnings\n")\ + TM(" 3 : Errors\n")\ + TM(" 4 : Critical\n")\ + TM(" Example: /P7.Verb=4\n")\ + TM(" /P7.Trc.Verb- Set verbosity level for all trace streams and associated modules\n")\ + TM(" Has next verbosity levels:\n")\ + TM(" 0 : Trace\n")\ + TM(" 1 : Debug\n")\ + TM(" 2 : Info\n")\ + TM(" 3 : Warnings\n")\ + TM(" 4 : Errors\n")\ + TM(" 5 : Critical\n")\ + TM(" Example: /P7.Trc.Verb=4\n")\ + TM(" /P7.Pool - Set size of the internal buffers pool in kilobytes. Minimal 16(kb)\n")\ + TM(" maximal is limited by your OS and HW. Default value = 4mb\n")\ + TM(" Example, 1 Mb allocation: /P7.Pool=1024\n")\ + TM(" -Sink=Baical, -Sink=Syslog : \n")\ + TM(" /P7.Addr - Set server address (IPV4, IPV6, NetBios name)\n")\ + TM(" Examples:\n")\ + TM(" /P7.Addr=127.0.0.1\n")\ + TM(" /P7.Addr=::1\n")\ + TM(" /P7.Addr=MyPC\n")\ + TM(" Default address is 127.0.0.1\n")\ + TM(" /P7.Port - Set server port, default port is 9009\n")\ + TM(" Example: /P7.Port=9010\n")\ + TM(" /P7.PSize - Set packet size. Min value 512 bytes, Max - 65535, Default - 512\n")\ + TM(" You should specify optimum packet size\n")\ + TM(" for your network, usually it is MTU.\n")\ + TM(" Example: /P7.PSize=1476\n")\ + TM(" -Sink=FileBin, -Sink=FileTxt: \n")\ + TM(" /P7.Dir - Directory where P7 files will be created, if it is not specified\n")\ + TM(" process directory will be used.\n")\ + TM(" Examples:\n")\ + TM(" /P7.Dir=/home/user/logs/\n")\ + TM(" /P7.Dir=C:\\Logs\\\n")\ + TM(" /P7.Files - defines maximum P7 logs files in destination folder\n")\ + TM(" in case if count of files is larger than specified value\n")\ + TM(" oldest files will be removed\n")\ + TM(" /P7.Roll - use it to specify files rolling value & type. There are 2 rolling types:\n")\ + TM(" * Rolling by file size, measured in megabytes\n")\ + TM(" * Rolling by time, measured in hours, 1000 hours max\n")\ + TM(" Rolling value consists of 2 parts:\n")\ + TM(" * digit\n")\ + TM(" * postfix: hr, mb\n")\ + TM(" Examples:\n")\ + TM(" /P7.Roll=100mb\n")\ + TM(" /P7.Roll=24hr\n")\ + TM(" -Sink=FileTxt, -Sink=Console, -Sink=Syslog: \n")\ + TM(" /P7.Format - log message format sting, example: /P7.Format=\"{%%cn} [%%tf] %%lv %%ms\"\n")\ + TM(" * cn - channel name \n")\ + TM(" * id - message ID\n")\ + TM(" * ix - message index\n")\ + TM(" * tf - full time YY.MM.DD HH.MM.SS.mils.mics.nans\n")\ + TM(" * tm - time medium HH.MM.SS.mils.mics.nans\n")\ + TM(" * ts - time short MM.SS.mils.mics.nans\n")\ + TM(" * td - time difference between current and prev. one +SS.mils.mics.nans\n")\ + TM(" * tc - time stamp in 100 nanoseconds intervals\n")\ + TM(" * lv - level (error, warning, etc)\n")\ + TM(" * ti - thread ID\n")\ + TM(" * tn - thread name\n")\ + TM(" * cc - CPU core\n")\ + TM(" * mi - module ID\n")\ + TM(" * mn - module name\n")\ + TM(" * ff - file path + name\n")\ + TM(" * fs - file name\n")\ + TM(" * fl - file line\n")\ + TM(" * fn - function name\n")\ + TM(" * ms - message\n")\ + TM(" -Sink=Null: \n")\ + TM(" there is no arguments\n")\ + + +//Error codes of P7 library, if you want to get extended information about error code please activate internal +//console(Linux)/file(Windows) logging. To activate it add parameter to client "/P7.Verb=0" +enum eP7_Error +{ + eP7_Error_None = 0, + eP7_Error_SharedObjectInvalid, + eP7_Error_MemoryAllocation, + eP7_Error_Network, + eP7_Error_OS, + eP7_Error_UserSettings, + eP7_Error_FolderCreation, + eP7_Error_FileCreation, + eP7_Error_NoClient, + eP7_Error_NoFreeChannels, + + eP7_Error_Max +}; + +enum eClient_Status +{ + //Regular statuses + ECLIENT_STATUS_OK = 0, + ECLIENT_STATUS_OFF , + ECLIENT_STATUS_INTERNAL_ERROR , + + //Temporary statuses + ECLIENT_STATUS_DISCONNECTED , + ECLIENT_STATUS_NO_FREE_BUFFERS , + ECLIENT_STATUS_NOT_ALLOWED , + ECLIENT_STATUS_WRONG_PARAMETERS , + ECLIENT_STATUS_WRONG_FORMAT +}; + +PRAGMA_PACK_ENTER(4) //alignment is now 4, MS Only////////////////////////////// + +struct sP7C_Status +{ + tBOOL bConnected; + //count of the connection drops, when connection has been reinitialized + tUINT32 dwResets; +}ATTR_PACK(4); + + +struct sP7C_Data_Chunk +{ + void *pData; + tUINT32 dwSize; +}ATTR_PACK(4); + + +struct sP7C_Channel_Info +{ + tUINT32 dwID; +}ATTR_PACK(4); + +struct sP7C_Info +{ + //sockaddr_storage sServer; + tUINT32 dwMem_Used; + tUINT32 dwMem_Free; + tUINT32 dwMem_Alloc; + tUINT32 dwReject_Mem; //chunks rejected counter - no memory + tUINT32 dwReject_Con; //chunks rejected counter - no connection + tUINT32 dwReject_Int; //chunks rejected counter - internal errors +}ATTR_PACK(4); + +PRAGMA_PACK_EXIT()//4/////////////////////////////////////////////////////////// + + +class /*__declspec(novtable)*/ IP7C_Channel +{ +public: + enum eType + { + eTrace, + eTelemetry, + eCount + }; + //////////////////////////////////////////////////////////////////////////// + //Get_Type - get channel type, depending on type cast to IP7_Telemetry or + // IP7_Trace is available + virtual IP7C_Channel::eType Get_Type() = 0; + + //////////////////////////////////////////////////////////////////////////// + //Add_Ref - increase object's reference count + // See documentation for details. + virtual tINT32 Add_Ref() = 0; + + //////////////////////////////////////////////////////////////////////////// + //Release - decrease object's reference count. If reference count less or + // equal to 0 - object will be destroyed + // See documentation for details. + virtual tINT32 Release() = 0; + + + virtual void On_Init(sP7C_Channel_Info *i_pInfo) = 0; + virtual void On_Receive(tUINT32 i_dwChannel, + tUINT8 *i_pBuffer, + tUINT32 i_dwSize, + tBOOL i_bBigEndian + ) = 0; + + virtual void On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus)=0; + + virtual void On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash) = 0; +}; + + +//Define the max channels count, and max packet size for IP7_Client::Sent(...) +#define USER_PACKET_CHANNEL_ID_BITS_COUNT (5) +#define USER_PACKET_SIZE_BITS_COUNT (32-USER_PACKET_CHANNEL_ID_BITS_COUNT) +#define USER_PACKET_MAX_SIZE (1 << USER_PACKET_SIZE_BITS_COUNT) +#define USER_PACKET_CHANNEL_ID_MAX_SIZE (1 << USER_PACKET_CHANNEL_ID_BITS_COUNT) + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class IP7_Client +{ +public: + enum eType + { + eBaical, + eFileBin, + eAuto, + eNull, + eText, + eCount + }; + virtual IP7_Client::eType Get_Type() = 0; + + virtual tINT32 Add_Ref() = 0; + virtual tINT32 Release() = 0; + + virtual eClient_Status Get_Status() = 0; + virtual tBOOL Get_Status(sP7C_Status *o_pStatus) = 0; + virtual tBOOL Get_Info(sP7C_Info *o_pInfo) = 0; + //N.B. If you use Baikal server to receive data - please do not mix + // different packets formats (Trace + Telemetry for example) on the same + // channel, in this case one data format will be dropped by server + virtual eClient_Status Register_Channel(IP7C_Channel *i_pChannel) = 0; + virtual eClient_Status Unregister_Channel(tUINT32 i_dwID) = 0; + + virtual eClient_Status Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Share - function to share current P7 object in address space of + // the current process, see documentation for details + virtual tBOOL Share(const tXCHAR *i_pName) = 0; + + virtual const tXCHAR *Get_Argument(const tXCHAR *i_pName) = 0; + + virtual size_t Get_Channels_Count() = 0; + virtual IP7C_Channel *Get_Channel(size_t i_szIndex) = 0; + + virtual void Flush() = 0; +}; + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Create_Client - function creates new P7 client. +//See documentation for details +//////////////////////////////////////////////////////////////////////////////// +//N.B: P7 client in addition will analyze your application command line and +// arguments specified through command line will have higher priority then +// i_sArgs arguments +extern "C" P7_EXPORT IP7_Client * __cdecl P7_Create_Client(const tXCHAR *i_pArgs); + + +//////////////////////////////////////////////////////////////////////////////// +//This functions allows you to get P7 instance if it was created by someone else +//inside current process. +//See documentation for details. +extern "C" P7_EXPORT IP7_Client * __cdecl P7_Get_Shared(const tXCHAR *i_pName); + + +//////////////////////////////////////////////////////////////////////////////// +//Retrieves the calling thread's last-error code value. The last-error code is +//maintained on a per-thread basis. Multiple threads do not overwrite each other's +//last-error code. +//N.B.: Error code will be reset after function call +extern "C" P7_EXPORT eP7_Error __cdecl P7_Last_Error(); + + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// P7 Crash processor // +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//This function setup crash handler to catch and process exceptions like +// * access violation/segmentation fault +// * division by zero +// * pure virtual call +// * etc. +//When crash occurs handler will call P7_Exceptional_Flush function automatically +extern "C" P7_EXPORT void __cdecl P7_Set_Crash_Handler(); + +//////////////////////////////////////////////////////////////////////////////// +//This function clears crash handler +extern "C" P7_EXPORT void __cdecl P7_Clr_Crash_Handler(); + + +//////////////////////////////////////////////////////////////////////////////// +//Function allows to flush (deliver) not delivered/saved P7 buffers for all +//opened clients and related channels owned by process in CASE OF your app/proc. +//crash. +//This function do not call system memory allocation functions only writes to +//file/socket. +//Classical scenario: your application has been crushed, you catch the moment of +//crush and call this function once. +//Has to be used if integrator implements own crash handling mechanism. +//N.B.: DO NOT USE OTHER P7 FUNCTION AFTER CALLING OF THIS FUNCTION +//See documentation for details. +extern "C" P7_EXPORT void __cdecl P7_Exceptional_Flush(); + + +//////////////////////////////////////////////////////////////////////////////// +//Function allows to flush (deliver) not delivered/saved P7 buffers for all +//opened clients and related channels owned by process. Please do not use this +//function often, it may reduce performance. +extern "C" P7_EXPORT void __cdecl P7_Flush(); + + +#endif //P7_CLIENT_H diff --git a/p7lib/Headers/P7_Cproxy.h b/p7lib/Headers/P7_Cproxy.h new file mode 100644 index 0000000..76c2f1c --- /dev/null +++ b/p7lib/Headers/P7_Cproxy.h @@ -0,0 +1,641 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provides access to P7 library functionality from C language/ +// or from any other language using dll/so interface / +// / +// +-------------------+ / +// | Sink | / +// | * Network (Baical)| / +// | * FileBin | / +// | * FileTxt | / +// | * Console | / +// | * Syslog | / +// | * Auto | / +// | * Null | / +// +---------^---------+ / +// | / +// | / +// +---------+---------+ / +// | P7 Client | / +// | [ Channels ] | / +// | +-+ +-+ +--+ | / +// | |0| |1| ...|31| | / +// | +^+ +^+ +-^+ | / +// +---|---|-------|---+ / +// | | | / +// +-----+ | +----------+ / +// | | | / +// | | | / +// +---+---+ +---+--------+ +---+---+ / +// | Trace | | Telemetry | | Trace | / +// |Channel| | channel | ... |Channel| / +// +-------+ +------------+ +-------+ / +// / +//////////////////////////////////////////////////////////////////////////////// +// // +// Documentation is located in /Documentation/P7.pdf // +// // +//////////////////////////////////////////////////////////////////////////////// +#ifndef P7_PROXY_H +#define P7_PROXY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7 client // +// // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + +typedef void* hP7_Client; + +typedef tUINT64 (__cdecl *fnGet_Time_Stamp)(void *i_pContext); +typedef void (__cdecl *fnConnect)(void *i_pContext, tBOOL i_bConnected); + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Create - function creates new P7 client, client is used as transport +//engine for telemetry & trace channels, every client can handle up to 32 +//channels. +//See documentation for details. +//////////////////////////////////////////////////////////////////////////////// +//N.B: P7 client in addition will analyze your application command line and +// arguments specified through command line will have higher priority then +// i_sArgs arguments +extern P7_EXPORT hP7_Client __cdecl P7_Client_Create(const tXCHAR *i_pArgs); + +//dll/so function prototype +typedef hP7_Client (__cdecl *fnP7_Client_Create)(const tXCHAR *i_pArgs); + + +//////////////////////////////////////////////////////////////////////////////// +//This functions allows you to get P7 client instance if it was created by +//someone else inside current process and shared using P7_Client_Share() func. +//If no instance was registered inside current process - function will return +//NULL. Do not forget to call P7_Client_Free() when you finish your work. +//See documentation for details. +extern P7_EXPORT hP7_Client __cdecl P7_Client_Get_Shared(const tXCHAR *i_pName); + +//dll/so function prototype +typedef hP7_Client (__cdecl *fnP7_Client_Get_Shared)(const tXCHAR *i_pName); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Share - function to share current P7 client object in address space +//of the current process, to get shared client use function P7_Client_Get_Shared +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Client_Share(hP7_Client i_hClient, + const tXCHAR *i_pName + ); +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Client_Share)(hP7_Client i_hClient, + const tXCHAR *i_pName + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Flush - function allows to flush (deliver) not delivered/saved P7 +//buffers for current client. Please do not use this function often, it may +//reduce performance. + +extern P7_EXPORT void __cdecl P7_Client_Flush(hP7_Client i_hClient); +//dll/so function prototype +typedef void (__cdecl *fnP7_Client_Flush)(hP7_Client i_hClient); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Add_Ref - increase reference counter for the client +//See documentation for details. +extern P7_EXPORT tINT32 __cdecl P7_Client_Add_Ref(hP7_Client i_hClient); + +//dll/so function prototype +typedef tINT32 (__cdecl *fnP7_Client_Add_Ref)(hP7_Client i_hClient); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Release - function release the client, reference counter technology +//See documentation for details. +extern P7_EXPORT tINT32 __cdecl P7_Client_Release(hP7_Client i_hClient); + +//dll/so function prototype +typedef tINT32 (__cdecl *fnP7_Client_Release)(hP7_Client i_hClient); + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// P7 Crash processor // +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//This function setup crash handler to catch and process exceptions like +// * access violation/segmentation fault +// * division by zero +// * pure virtual call +// * etc. +//When crash occurs handler will call P7_Exceptional_Flush function automatically +extern P7_EXPORT void __cdecl P7_Set_Crash_Handler(); + +//dll/so function prototype +typedef void (__cdecl *fnP7_Set_Crash_Handler)(); + +//////////////////////////////////////////////////////////////////////////////// +//This function clears crash handler +extern P7_EXPORT void __cdecl P7_Clr_Crash_Handler(); + +//dll/so function prototype +typedef void (__cdecl *fnP7_Clr_Crash_Handler)(); + + +//////////////////////////////////////////////////////////////////////////////// +//Function allows to flush (deliver) not delivered/saved P7 buffers for all +//opened clients and related channels owned by process in CASE OF your app/proc. +//crash. +//This function do not call system memory allocation functions only writes to +//file/socket. +//Classical scenario: your application has been crushed, you catch the moment of +//crush and call this function once. +//Has to be used if integrator implements own crash handling mechanism. +//N.B.: DO NOT USE OTHER P7 FUNCTION AFTER CALLING OF THIS FUNCTION +//See documentation for details. +extern P7_EXPORT void __cdecl P7_Exceptional_Flush(); + +//dll/so function prototype +typedef void (__cdecl *fnP7_Exceptional_Flush)(); + + +//////////////////////////////////////////////////////////////////////////////// +//Function allows to flush (deliver) not delivered/saved P7 buffers for all +//opened clients and related channels owned by process. Please do not use this +//function offten, it may reduce performance. +extern P7_EXPORT void __cdecl P7_Flush(); + +//dll/so function prototype +typedef void (__cdecl *fnP7_Flush)(); + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7 Telemetry // +// // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +typedef void* hP7_Telemetry; + +typedef void (__cdecl *fnTelemetry_Enable)(void *i_pContext, tUINT16 i_wId, tBOOL i_bEnable); + +typedef struct +{ + void *pContext; //context to be passed back to callbacks + tUINT64 qwTimestamp_Frequency; //count ticks per second, works in cooperation with pTimestamp_Callback + fnGet_Time_Stamp pTimestamp_Callback; //callback for getting user timestamps, works in cooperation with qwTimestamp_Frequency + fnTelemetry_Enable pEnable_Callback; //Callback to notify user when counter has been enables/disabled remotely + fnConnect pConnect_Callback; //Callback notifies user when connection with Baical is established/closed +} stTelemetry_Conf; + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Create - function create new instance of IP7_Telemetry object +//See documentation for details. +extern P7_EXPORT hP7_Telemetry __cdecl P7_Telemetry_Create(hP7_Client i_hClient, + const tXCHAR *i_pName, + const stTelemetry_Conf *i_pConf + ); + +//dll/so function prototype +typedef hP7_Telemetry (__cdecl *fnP7_Telemetry_Create)(hP7_Client i_hClient, + const tXCHAR *i_pName, + const stTelemetry_Conf *i_pConf + ); + + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Share - function to share current P7 telemetry object in address +//space of the current process, to get shared client use function +//P7_Telemetry_Get_Shared +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Telemetry_Share(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Telemetry_Share)(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName + ); + + +//////////////////////////////////////////////////////////////////////////////// +//This functions allow you to get P7 telemetry instance if it was created by +//someone other inside current process. If no instance was registered inside +//current process - function will return NULL. Do not forget to call Release +//on interface when you finish your work +//See documentation for details. +extern P7_EXPORT hP7_Telemetry __cdecl P7_Telemetry_Get_Shared(const tXCHAR *i_pName); + +//dll/so function prototype +typedef hP7_Telemetry (__cdecl *fnP7_Telemetry_Get_Shared)(const tXCHAR *i_pName); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Create_Counter - create new telemetry counter, max amount of +//counters - 256, if you need more - we recommends you to create another telem. +//channel using P7_Telemetry_Create() function +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Telemetry_Create_Counter(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + tBOOL i_bOn, + tUINT16 *o_pID + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Telemetry_Create_Counter)(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + tBOOL i_bOn, + tUINT16 *o_pID + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Put_Value - add counter smaple value +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Telemetry_Put_Value(hP7_Telemetry i_hTelemetry, + tUINT16 i_wCounter_ID, + tDOUBLE i_dbValue + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Telemetry_Put_Value)(hP7_Telemetry i_hTelemetry, + tUINT16 i_wCounter_ID, + tDOUBLE i_dbValue + ); + + +//////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Find_Counter - find counter ID by name +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Telemetry_Find_Counter(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName, + tUINT16 *o_pCounter_ID + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Telemetry_Find_Counter)(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName, + tUINT16 *o_pCounter_ID + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Add_Ref - increase reference counter for the telemetry channel +//See documentation for details. +extern P7_EXPORT tINT32 __cdecl P7_Telemetry_Add_Ref(hP7_Telemetry i_hTelemetry); + +//dll/so function prototype +typedef tINT32 (__cdecl *fnP7_Telemetry_Add_Ref)(hP7_Telemetry i_hTelemetry); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Release - function releases the telemetry, reference counter +//technology is used, it mean the same client instance can be used from few +//program parts, and every instance has to be released to completely destroy the +//P7 telemetry object +//See documentation for details. +extern P7_EXPORT tINT32 __cdecl P7_Telemetry_Release(hP7_Telemetry i_hTelemetry); + +//dll/so function prototype +typedef tINT32 (__cdecl *fnP7_Telemetry_Release)(hP7_Telemetry i_hTelemetry); + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7 Trace // +// // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +typedef void* hP7_Trace; +typedef void* hP7_Trace_Module; + +//////////////////////////////////////////////////////////////////////////////// +//Trace levels: +#define P7_TRACE_LEVEL_TRACE 0 +#define P7_TRACE_LEVEL_DEBUG 1 +#define P7_TRACE_LEVEL_INFO 2 +#define P7_TRACE_LEVEL_WARNING 3 +#define P7_TRACE_LEVEL_ERROR 4 +#define P7_TRACE_LEVEL_CRITICAL 5 + + +typedef void (__cdecl *fnTrace_Verbosity)(void *i_pContext, + hP7_Trace_Module i_hModule, + tUINT32 i_dwVerbosity); + +typedef struct +{ + void *pContext; //context to be passed back to callbacks + tUINT64 qwTimestamp_Frequency; //count ticks per second, works in cooperation with pTimestamp_Callback + fnGet_Time_Stamp pTimestamp_Callback; //callback for getting user timestamps, works in cooperation with qwTimestamp_Frequency + fnTrace_Verbosity pVerbosity_Callback; //Callback to notify user when verbosity has been changed + fnConnect pConnect_Callback; //Callback notifies user when connection with Baical is established/closed +} stTrace_Conf; + + +//////////////////////////////////////////////////////////////////////////////// +//P7_TRACE_ADD macro for trace function calling simplification +#define P7_TRACE_ADD(i_hTrace,\ + i_wID,\ + i_eLevel,\ + i_dwModuleID,\ + i_pFormat,\ + ...)\ + P7_Trace_Add(i_hTrace,\ + i_wID,\ + i_eLevel,\ + i_dwModuleID,\ + (tUINT16)__LINE__,\ + __FILE__,\ + __FUNCTION__,\ + i_pFormat,\ + __VA_ARGS__) + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Create_Trace - function create new instance of IP7_Trace object +//See documentation for details. +extern P7_EXPORT hP7_Trace __cdecl P7_Trace_Create(hP7_Client i_hClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf + ); + +//dll/so function prototype +typedef hP7_Trace (__cdecl *fnP7_Trace_Create)(hP7_Client i_hClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf + ); + + +//////////////////////////////////////////////////////////////////////////////// +//This functions allow you to get P7 trace instance if it was created by someone +//other inside current process. If no instance was registered inside current +//process - function will return NULL. Do not forget to call Release +//on interface when you finish your work +//See documentation for details. +extern P7_EXPORT hP7_Trace __cdecl P7_Trace_Get_Shared(const tXCHAR *i_pName); + +//dll/so function prototype +typedef hP7_Trace (__cdecl *fnP7_Trace_Get_Shared)(const tXCHAR *i_pName); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Share - function to share current P7 trace object in address space of +//the current process, to get shared trace channel use function +//P7_Trace_Get_Shared() +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Trace_Share(hP7_Trace i_hTrace, + const tXCHAR *i_pName + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Trace_Share)(hP7_Trace i_hTrace, + const tXCHAR *i_pName + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Set_Verbosity - function to set minimal trace verbosity, all traces +//with less priority will be rejected by channel. You may set verbosity online +//from Baical server +//See documentation for details. +extern P7_EXPORT void __cdecl P7_Trace_Set_Verbosity(hP7_Trace i_hTrace, + hP7_Trace_Module i_hModule, + tUINT32 i_dwVerbosity + ); + + +//dll/so function prototype +typedef void (__cdecl *fnP7_Trace_Set_Verbosity)(hP7_Trace i_hTrace, + hP7_Trace_Module i_hModule, + tUINT32 i_dwVerbosity + ); + + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Get_Verbosity - function to get minimal trace verbosity +//See documentation for details. +extern P7_EXPORT tUINT32 __cdecl P7_Trace_Get_Verbosity(hP7_Trace i_hTrace, + hP7_Trace_Module i_hModule + ); + +//dll/so function prototype +typedef tUINT32 (__cdecl *fnP7_Trace_Get_Verbosity)(hP7_Trace i_hTrace, + hP7_Trace_Module i_hModule); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Register_Thread - function used to specify name for current/special +//thread. +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Trace_Register_Thread(hP7_Trace i_hTrace, + const tXCHAR *i_pName, + tUINT32 i_dwThreadId + ); + + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Trace_Register_Thread)(hP7_Trace i_hTrace, + const tXCHAR *i_pName, + tUINT32 i_dwThreadId + ); + + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Unregister_Thread - function used to unregister current/special thread. +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Trace_Unregister_Thread(hP7_Trace i_hTrace, + tUINT32 i_dwThreadId + ); + + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Trace_Unregister_Thread)(hP7_Trace i_hTrace, + tUINT32 i_dwThreadId + ); + + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Register_Module - function used to register module for following usage +//by P7_Trace_Add/P7_Trace_Embedded/P7_Trace_Managed functions +//See documentation for details. +extern P7_EXPORT hP7_Trace_Module __cdecl P7_Trace_Register_Module(hP7_Trace i_hTrace, + const tXCHAR *i_pName + ); + + +//dll/so function prototype +typedef hP7_Trace_Module (__cdecl *fnP7_Trace_Register_Module)(hP7_Trace i_hTrace, + const tXCHAR *i_pName + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Add - send trace message to Baical server. +//You may use macro P7_TRACE_ADD to simplify calling of this function +//////////////////////////////////////////////////////////////////////////////// +//N.B.: DO NOT USE VARIABLE for format string! You should always use CONSTANT +// TEXT like L"My Format %d, %s" +// USE THIS FUNCTION ONLY FROM C/C++ LANGUAGES! If you want to use trace +// functionality from other languages please call Trace_Managed() function +//////////////////////////////////////////////////////////////////////////////// +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Trace_Add(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR *i_pFormat, + ... + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Trace_Add)(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR *i_pFormat, + ... + ); + + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Embedded - send trace message to Baical server. +//this function is a copy of P7_Trace_Add function, but it is dedicated for +//embedding into your log function with variable arguments list: +//Usage scenario: you already have function with variable arguments, but body of +//your function may be replaced by Trace_Embedded. +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Trace_Embedded(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Trace_Embedded)(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Managed - send trace message to Baical server. +//This function is intended for use by MANAGED languages like C#, Python, etc +//It is slightly slower than P7_Trace_Add. +//See documentation for details. +extern P7_EXPORT tBOOL __cdecl P7_Trace_Managed(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + const tXCHAR *i_pMessage + ); + +//dll/so function prototype +typedef tBOOL (__cdecl *fnP7_Trace_Managed)(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + const tXCHAR *i_pMessage + ); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Add_Ref - increase reference counter for the telemetry channel +//See documentation for details. +extern P7_EXPORT tINT32 __cdecl P7_Trace_Add_Ref(hP7_Trace i_hTrace); + +//dll/so function prototype +typedef tINT32 (__cdecl *fnP7_Trace_Add_Ref)(hP7_Trace i_hTrace); + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Release - function releases the trace object, reference counter +//technology is used, it mean the same trace instance can be used from few +//program parts, and every instance has to be released to completely destroy the +//P7 trace object +//See documentation for details. +extern P7_EXPORT tINT32 __cdecl P7_Trace_Release(hP7_Trace i_hTrace); + +//dll/so function prototype +typedef tINT32 (__cdecl *fnP7_Trace_Release)(hP7_Trace i_hTrace); + + +#ifdef __cplusplus +} +#endif + +#endif //P7_PROXY_H diff --git a/p7lib/Headers/P7_Extensions.h b/p7lib/Headers/P7_Extensions.h new file mode 100644 index 0000000..2c569e0 --- /dev/null +++ b/p7lib/Headers/P7_Extensions.h @@ -0,0 +1,490 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// P7 extensions - interfaces to some additional functionality / +// - IP7_Trace : traces formatting and delivery to Baical server / +//////////////////////////////////////////////////////////////////////////////// +#ifndef P7_EXTENSIONS_H +#define P7_EXTENSIONS_H + + +#define P7_EXTENSION_TYPE_BITS_COUNT (5) +#define P7_EXTENSION_SUB_TYPE_BITS_COUNT (5) +#define P7_EXTENSION_PACKET_SIZE_BITS_COUNT (22) + +#define P7_EXTENSION_MAX_TYPES (1 << P7_EXTENSION_TYPE_BITS_COUNT) + +#define P7TRACE_NAME_LENGTH (64) +#define P7TRACE_THREAD_NAME_LENGTH (48) +#define P7TRACE_MODULE_NAME_LENGTH (54) +#define P7TELEMETRY_NAME_LENGTH (64) + +#define P7TELEMETRY_COUNTER_NAME_LENGTH_V1 (64) +#define P7TELEMETRY_COUNTERS_MAX_COUNT_V1 ((tUINT8)~((tUINT8)0)) +#define P7TELEMETRY_INVALID_ID_V1 (P7TELEMETRY_COUNTERS_MAX_COUNT_V1 - 1) + +#define P7TELEMETRY_INVALID_ID_V2 ((tUINT16)~((tUINT16)0)) +#define P7TELEMETRY_COUNTERS_MAX_COUNT_V2 ((tUINT16)~((tUINT16)0)) +#define P7TELEMETRY_COUNTER_NAME_MIN_LENGTH_V2 (2) + + +#define P7TRACE_INFO_FLAG_BIG_ENDIAN (0x0001) +#define P7TRACE_INFO_FLAG_UNSORTED (0x0002) +#define P7TRACE_INFO_FLAG_EXTENTION (0x0004) +#define P7TRACE_INFO_FLAG_TIME_ZONE (0x0008) + +#define P7TELEMETRY_FLAG_EXTENTION (0x0001) +#define P7TELEMETRY_FLAG_TIME_ZONE (0x0002) + + +enum eTrace_Arg_Type +{ + P7TRACE_ARG_TYPE_UNK = 0x00, + P7TRACE_ARG_TYPE_CHAR = 0x01, + P7TRACE_ARG_TYPE_INT8 = 0x01, + P7TRACE_ARG_TYPE_CHAR16 ,//(0x02) + P7TRACE_ARG_TYPE_INT16 ,//(0x03) + P7TRACE_ARG_TYPE_INT32 ,//(0x04) + P7TRACE_ARG_TYPE_INT64 ,//(0x05) + P7TRACE_ARG_TYPE_DOUBLE ,//(0x06) + P7TRACE_ARG_TYPE_PVOID ,//(0x07) + P7TRACE_ARG_TYPE_USTR16 ,//(0x08) //unicode - UTF16 string + P7TRACE_ARG_TYPE_STRA ,//(0x09) //ASCII string + P7TRACE_ARG_TYPE_USTR8 ,//(0x0A) //unicode - UTF8 string + P7TRACE_ARG_TYPE_USTR32 ,//(0x0B) //unicode - UTF32 string + P7TRACE_ARG_TYPE_CHAR32 ,//(0x0C) + P7TRACE_ARG_TYPE_INTMAX ,//(0x0D) + + P7TRACE_ARGS_COUNT +}; + + +#if defined(GTX64) + #define SIZE_OF_ARG(t) ( (sizeof(t) + 8 - 1) & ~(8 - 1) ) + + typedef tUINT64 tKeyType; +#else + #define SIZE_OF_ARG(t) ( (sizeof(t) + 4 - 1) & ~(4 - 1) ) + + typedef tUINT32 tKeyType; +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// Data types, we can transmit different packets types, here are the list +// of all supported for the moment packet types +enum eP7User_Type +{ + EP7USER_TYPE_TRACE = 0, + EP7USER_TYPE_TELEMETRY_V1 , + EP7USER_TYPE_TELEMETRY_V2 , + + EP7USER_TYPE_MAX = P7_EXTENSION_MAX_TYPES +}; + + +//////////////////////////////////////////////////////////////////////////////// +enum eP7Trace_Type +{ + EP7TRACE_TYPE_INFO = 0, //Client->Server + EP7TRACE_TYPE_DESC , //Client->Server + EP7TRACE_TYPE_DATA , //Client->Server + EP7TRACE_TYPE_VERB , //Client->Server->Client + EP7TRACE_TYPE_CLOSE , //Client->Server + EP7TRACE_TYPE_THREAD_START , //Client->Server + EP7TRACE_TYPE_THREAD_STOP , //Client->Server + EP7TRACE_TYPE_MODULE , //Client->Server + EP7TRACE_TYPE_DELETE , //Server->Client + EP7TRACE_TYPE_UTC_OFFS , //Client->Server + + EP7TRACE_TYPE_MAX = 32 +}; + +//////////////////////////////////////////////////////////////////////////////// +enum eP7Trace_Ext +{ + EP7TRACE_EXT_MODULE_ID = 0, + EP7TRACE_EXT_MAX = 256 +}; + + +//////////////////////////////////////////////////////////////////////////////// +enum eP7Tel_Type +{ + EP7TEL_TYPE_INFO = 0, //Client->Server + EP7TEL_TYPE_COUNTER , //Client->Server + EP7TEL_TYPE_VALUE , //Client->Server + EP7TEL_TYPE_ENABLE , //Server->Client + EP7TEL_TYPE_CLOSE , //Client->Server + EP7TEL_TYPE_DELETE , //Server->Client + EP7TEL_TYPE_UTC_OFFS , //Client->Server + + EP7TEL_TYPE_MAX = 32 +}; + + +PRAGMA_PACK_ENTER(4) //alignment is now 4, MS Only////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// common user header for extensions (like trace or telemetry) + +#define INIT_EXT_HEADER(iHeaderRaw, iType, iSubType, iSize)\ + iHeaderRaw.dwBits = \ + (((iType) & ((1 << P7_EXTENSION_TYPE_BITS_COUNT) - 1)) |\ + (((iSubType) & ((1 << P7_EXTENSION_SUB_TYPE_BITS_COUNT) - 1)) << P7_EXTENSION_TYPE_BITS_COUNT) |\ + (((iSize) & ((1 << P7_EXTENSION_PACKET_SIZE_BITS_COUNT) - 1)) << (P7_EXTENSION_TYPE_BITS_COUNT + P7_EXTENSION_SUB_TYPE_BITS_COUNT))) + +#define GET_EXT_HEADER_SIZE(iHeaderRaw)\ + (iHeaderRaw.dwBits >> (P7_EXTENSION_TYPE_BITS_COUNT + P7_EXTENSION_SUB_TYPE_BITS_COUNT)) + +#define GET_EXT_HEADER_TYPE(iHeaderRaw)\ + (iHeaderRaw.dwBits & ((1 << P7_EXTENSION_TYPE_BITS_COUNT) - 1)) + +#define GET_EXT_HEADER_SUBTYPE(iHeaderRaw)\ + ((iHeaderRaw.dwBits >> P7_EXTENSION_TYPE_BITS_COUNT) & ((1 << P7_EXTENSION_SUB_TYPE_BITS_COUNT) - 1)) + +#define SET_EXT_HEADER_SIZE(iHeaderRaw, iSize)\ + iHeaderRaw.dwBits = \ + (iHeaderRaw.dwBits & ((1 << (P7_EXTENSION_TYPE_BITS_COUNT + P7_EXTENSION_SUB_TYPE_BITS_COUNT)) - 1)) |\ + (((iSize) & ((1 << P7_EXTENSION_PACKET_SIZE_BITS_COUNT) - 1)) << (P7_EXTENSION_TYPE_BITS_COUNT + P7_EXTENSION_SUB_TYPE_BITS_COUNT)) + +struct sP7Ext_Header +{ + tUINT32 dwType :P7_EXTENSION_TYPE_BITS_COUNT; //eP7User_Type + tUINT32 dwSubType:P7_EXTENSION_SUB_TYPE_BITS_COUNT; + //max 4 mb, value should include size of this header + tUINT32 dwSize :P7_EXTENSION_PACKET_SIZE_BITS_COUNT; + //At the end of structure we put serialized data +} ATTR_PACK(4); + +struct sP7Ext_Raw //mapping of sP7Ext_Header +{ + tUINT32 dwBits; +} ATTR_PACK(4); + +GASSERT(sizeof(sP7Ext_Header) == sizeof(sP7Ext_Raw)); + +//N.B.: extension packets can follow one by one in data packets. +PRAGMA_PACK_EXIT()//4/////////////////////////////////////////////////////////// + + + +PRAGMA_PACK_ENTER(2) //alignment is now 2, MS Only////////////////////////////// + +#define P7_DAMP_FILE_MARKER_V1 (0x45D2AC71ECF32CA6ULL) +#define P7_DAMP_FILE_HOST_LENGTH (256) +#define P7_DAMP_FILE_PROCESS_LENGTH (256) + +//P7 damp file header +struct sP7File_Header +{ + tUINT64 qwMarker; + tUINT32 dwProcess_ID; + tUINT32 dwProcess_Start_Time_Hi; + tUINT32 dwProcess_Start_Time_Lo; + tWCHAR pProcess_Name[P7_DAMP_FILE_PROCESS_LENGTH]; + tWCHAR pHost_Name[P7_DAMP_FILE_HOST_LENGTH]; +} ATTR_PACK(2); + + + +//////////////////////////////////////////////////////////////////////////////// +// Trace // +//////////////////////////////////////////////////////////////////////////////// + +//trace info header +struct sP7Trace_Info +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + //Contains a 64-bit value representing the number of 100-nanosecond intervals + //since January 1, 1601 (UTC). In windows we use FILETIME structure for + //representing + tUINT32 dwTime_Hi; + tUINT32 dwTime_Lo; + //Hi resolution timer value, we get this value when we retrieve current time. + //using difference between this value and timer value for every trace we can + //calculate time of the trace event with hi resolution + tUINT64 qwTimer_Value; + //timer's count heartbeats in second + tUINT64 qwTimer_Frequency; + tUINT64 qwFlags; + tWCHAR pName[P7TRACE_NAME_LENGTH]; +} ATTR_PACK(2); + + +//this structure describe each argument inside variable arguments list +//all arguments are serialized data block +struct sP7Trace_Arg +{ + //argument's type - one of P7TRACE_ARG_TYPE_XXX + tUINT8 bType; + //Size - how many bytes is used by argument inside block, this value is not + // directly depend on type, usually it depend on processor architecture + // for example "char" on WIN32 this is 4 bytes, but for EventTrace + // engine this is only 1 byte. + // N.B.: All strings has 0 size. + tUINT8 bSize; +} ATTR_PACK(2); + +//trace description header +struct sP7Trace_Format +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT16 wID; + tUINT16 wLine; + tUINT16 wModuleID; //Module ID, who send trace + tUINT16 wArgs_Len; //arguments count + //At the end of structure we put serialized data: + //sP7Trace_Arg [dwArgs_Len] - array of arguments + //wchar_t Format[] - null terminated string + //char FileName[] - null terminated string + //char FunctionName[] - null terminated string +} ATTR_PACK(2); + +//trace data header +struct sP7Trace_Data +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT16 wID; //trace ID + tUINT8 bLevel; //eP7Trace_Level + tUINT8 bProcessor; //Processor number + tUINT32 dwThreadID; //Thread ID + tUINT32 dwSequence; //sequence number + tUINT64 qwTimer; //High resolution timer value + //At the end of structure we put serialized data: + // - trace variable arguments values + // - extensions [data X bits][type 8 bits], [data X bits][type 8 bits], ... [count 8 bits] +} ATTR_PACK(2); + +//trace ext header for Module ID +struct sP7Trace_Ext_Mid +{ + tUINT16 wMID; +} ATTR_PACK(2); + + +//trace verbosity header +struct sP7Trace_Verb +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + eP7Trace_Level eVerbosity; + tUINT16 wModuleID; +} ATTR_PACK(2); + + +//Thread start info +struct sP7Trace_Thread_Start +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT32 dwThreadID; //Thread ID + tUINT64 qwTimer; //High resolution timer value + char pName[P7TRACE_THREAD_NAME_LENGTH]; //Thread name (UTF-8) +} ATTR_PACK(2); + +//Thread stop info +struct sP7Trace_Thread_Stop +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT32 dwThreadID; //Thread ID + tUINT64 qwTimer; //High resolution timer value +} ATTR_PACK(2); + +//Module info +struct sP7Trace_Module +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT16 wModuleID; + eP7Trace_Level eVerbosity; + char pName[P7TRACE_MODULE_NAME_LENGTH]; //name (UTF-8) +} ATTR_PACK(2); + + +//Time zone description +struct sP7Trace_Utc_Offs +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tINT32 iUtcOffsetSec; +} ATTR_PACK(2); + +//////////////////////////////////////////////////////////////////////////////// +// Telemetry // +//////////////////////////////////////////////////////////////////////////////// + +//telemetry info header +struct sP7Tel_Info +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + //Contains a 64-bit value representing the number of 100-nanosecond intervals + //since January 1, 1601 (UTC). In windows we use FILETIME structure for + //representing + tUINT32 dwTime_Hi; + tUINT32 dwTime_Lo; + //Hi resolution timer value, we get this value when we retrieve current time. + //using difference between this value and timer value for every trace we can + //calculate time of the trace event with hi resolution + tUINT64 qwTimer_Value; + //timer's count heartbeats in second + tUINT64 qwTimer_Frequency; + tUINT64 qwFlags; + tWCHAR pName[P7TELEMETRY_NAME_LENGTH]; +} ATTR_PACK(2); + + +//Telemetry counter description +struct sP7Tel_Counter_v1 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT8 bID; + tUINT8 bOn; + tINT64 llMin; + tINT64 llMax; + tINT64 llAlarm; + tWCHAR pName[P7TELEMETRY_COUNTER_NAME_LENGTH_V1]; +} ATTR_PACK(2); + + +//Telemetry counter description +struct sP7Tel_Counter_v2 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + + tUINT16 wID; + tUINT16 bOn; + tDOUBLE dbMin; + tDOUBLE dbAlarmMin; + tDOUBLE dbMax; + tDOUBLE dbAlarmMax; + tWCHAR pName[P7TELEMETRY_COUNTER_NAME_MIN_LENGTH_V2]; +} ATTR_PACK(2); + +//telemetry counter On/Off verbosity header +struct sP7Tel_Enable_v1 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT8 bID; + tUINT8 bOn; +} ATTR_PACK(2); + + +//telemetry counter On/Off verbosity header +struct sP7Tel_Enable_v2 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT16 wID; + tUINT16 bOn; +} ATTR_PACK(2); + + +//Telemetry counter value +struct sP7Tel_Value_v1 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT8 bID; + tUINT8 bSeqN; + tUINT64 qwTimer; //High resolution timer value + tINT64 llValue; +} ATTR_PACK(2); + +//Telemetry counter value +struct sP7Tel_Value_v2 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tUINT16 wID; + tUINT16 wSeqN; + tUINT64 qwTimer; //High resolution timer value + tDOUBLE dbValue; +} ATTR_PACK(2); + + +//Time zone description +struct sP7Tel_Utc_Offs_V2 +{ + union + { + sP7Ext_Header sCommon; + sP7Ext_Raw sCommonRaw; + }; + tINT32 iUtcOffsetSec; +} ATTR_PACK(2); + + +PRAGMA_PACK_EXIT()//2/////////////////////////////////////////////////////////// + + +#endif //P7_EXTENSIONS_H diff --git a/p7lib/Headers/P7_Telemetry.h b/p7lib/Headers/P7_Telemetry.h new file mode 100644 index 0000000..23dbad6 --- /dev/null +++ b/p7lib/Headers/P7_Telemetry.h @@ -0,0 +1,118 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7.Telemetry // +// // +//////////////////////////////////////////////////////////////////////////////// +// // +// Documentation is located in /Documentation/P7.pdf // +// // +//////////////////////////////////////////////////////////////////////////////// +#ifndef P7_TELEMETRY_H +#define P7_TELEMETRY_H + +#include "P7_Client.h" +#include "P7_Cproxy.h" + +#define TELEMETRY_DEFAULT_SHARED_NAME TM("P7.Telemetry") + +//////////////////////////////////////////////////////////////////////////////// +///////////////////////////IP7_Telemetry//////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +class IP7_Telemetry + : public IP7C_Channel +{ +public: + //////////////////////////////////////////////////////////////////////////// + //Create - creates new telemetry counter, max amount of counters per + // telemetry instance - 256 + // See documentation for details. + virtual tBOOL Create(const tXCHAR *i_pName, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + tBOOL i_bOn, + tUINT16 *o_pID + ) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Add - add counter sample + // See documentation for details. + virtual tBOOL Add(tUINT16 i_bID, tDOUBLE i_llValue) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Find - find counter ID by name (case sensitive) + // See documentation for details. + virtual tBOOL Find(const tXCHAR *i_pName, tUINT16 *o_pID) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Set_Enable - enable or disable counter + virtual tBOOL Set_Enable(tUINT16 i_wID, tBOOL i_bEnable) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Get_Enable - get enable flag + virtual tBOOL Get_Enable(tUINT16 i_wID) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Get_Min - get min value + virtual tDOUBLE Get_Min(tUINT16 i_wID) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Get_Max - get max value + virtual tDOUBLE Get_Max(tUINT16 i_wID) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Get_Name - get name + virtual const tXCHAR *Get_Name(tUINT16 i_wID) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Get_Count - get amount of counters + virtual tUINT16 Get_Count() = 0; + + //////////////////////////////////////////////////////////////////////////// + //Share - function to share current P7.Telemetry object in address space of + // the current process, to get shared instance use function + // P7_Get_Shared_Telemetry(tXCHAR *i_pName) + // See documentation for details. + virtual tBOOL Share(const tXCHAR *i_pName) = 0; +}; + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Create_Telemetry - function creates new instance of IP7_Telemetry object +// See documentation for details. +extern "C" P7_EXPORT IP7_Telemetry* __cdecl P7_Create_Telemetry(IP7_Client *i_pClient, + const tXCHAR *i_pName, + const stTelemetry_Conf *i_pConf = NULL + ); + + +//////////////////////////////////////////////////////////////////////////////// +//This functions allows you to get P7 telemetry instance if it was created by +//someone else inside current process. If no instance was registered inside +//current process - function will return NULL. Do not forget to call Release on +//interface when you finish your work +//See documentation for details. +extern "C" P7_EXPORT IP7_Telemetry* __cdecl P7_Get_Shared_Telemetry(const tXCHAR *i_pName); + + +#endif //P7_TELEMETRY_H diff --git a/p7lib/Headers/P7_Trace.h b/p7lib/Headers/P7_Trace.h new file mode 100644 index 0000000..46f5435 --- /dev/null +++ b/p7lib/Headers/P7_Trace.h @@ -0,0 +1,281 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7.Tace // +// // +//////////////////////////////////////////////////////////////////////////////// +// // +// Documentation is located in /Documentation/P7.pdf // +// // +//////////////////////////////////////////////////////////////////////////////// +#ifndef P7_TRACE_H +#define P7_TRACE_H + +#include "P7_Client.h" +#include "P7_Cproxy.h" +#include + +#define TRACE_DEFAULT_SHARED_NAME TM("P7.Trace") + +//////////////////////////////////////////////////////////////////////////////// +//P7.Trace uses optimization to read variable arguments directly from the stack/ +//but some systems optimizes storing of var.args and uses processor resistors/ +//stack re-ordering, extra-padding and other techniques, so if you detect than / +//library print wrong values - please activate this macro manually for your / +//platform/project / +//////////////////////////////////////////////////////////////////////////////// +//#define P7TRACE_NO_VA_ARG_OPTIMIZATION + +//disable va_arg optimization for Linux, too many ways how GCC + Linux uses +//stack and registers to store va_arg +#if defined(__linux__) + #define P7TRACE_NO_VA_ARG_OPTIMIZATION +#endif + +//////////////////////////////////////////////////////////////////////////////// +//in some platforms access to 64 not aligned variable is illegal, if it the/ +//case please active the macro / +//////////////////////////////////////////////////////////////////////////////// +//#define P7TRACE_64BITS_ALIGNED_ACCESS + + +//////////////////////////////////////////////////////////////////////////////// +enum eP7Trace_Level +{ + EP7TRACE_LEVEL_TRACE = 0, + EP7TRACE_LEVEL_DEBUG , + EP7TRACE_LEVEL_INFO , + EP7TRACE_LEVEL_WARNING , + EP7TRACE_LEVEL_ERROR , + EP7TRACE_LEVEL_CRITICAL , + + EP7TRACE_LEVEL_COUNT +}; + + +//////////////////////////////////////////////////////////////////////////////// +#define P7_DELIVER(i_wID, i_eLevel, i_hModule, ...) Trace(i_wID,\ + i_eLevel,\ + i_hModule,\ + (tUINT16)__LINE__,\ + __FILE__,\ + __FUNCTION__,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define P7_QTRACE(i_wID, i_hModule, ...) P7_DELIVER(i_wID,\ + EP7TRACE_LEVEL_TRACE,\ + i_hModule,\ + __VA_ARGS__) + +#define P7_TRACE(i_hModule, ...) P7_QTRACE(0,\ + i_hModule,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define P7_QDEBUG(i_wID, i_hModule, ...) P7_DELIVER(i_wID,\ + EP7TRACE_LEVEL_DEBUG,\ + i_hModule,\ + __VA_ARGS__) + +#define P7_DEBUG(i_hModule, ...) P7_QDEBUG(0,\ + i_hModule,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define P7_QINFO(i_wID, i_hModule, ...) P7_DELIVER(i_wID,\ + EP7TRACE_LEVEL_INFO,\ + i_hModule,\ + __VA_ARGS__) + +#define P7_INFO(i_hModule, ...) P7_QINFO(0,\ + i_hModule,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define P7_QWARNING(i_wID, i_hModule, ...) P7_DELIVER(i_wID,\ + EP7TRACE_LEVEL_WARNING,\ + i_hModule,\ + __VA_ARGS__) + +#define P7_WARNING(i_hModule, ...) P7_QWARNING(0,\ + i_hModule,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define P7_QERROR(i_wID, i_hModule, ...) P7_DELIVER(i_wID,\ + EP7TRACE_LEVEL_ERROR,\ + i_hModule,\ + __VA_ARGS__) + +#define P7_ERROR(i_hModule, ...) P7_QERROR(0,\ + i_hModule,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define P7_QCRITICAL(i_wID, i_hModule, ...) P7_DELIVER(i_wID,\ + EP7TRACE_LEVEL_CRITICAL,\ + i_hModule,\ + __VA_ARGS__) + +#define P7_CRITICAL(i_hModule, ...) P7_QCRITICAL(0,\ + i_hModule,\ + __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +#define LOG(logger, level, format, ...) logger->P7_DELIVER(0, EP7TRACE_LEVEL_##level, NULL, TM(format), __VA_ARGS__) + +//////////////////////////////////////////////////////////////////////////////// +/////////////////////////////IP7_Trace////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +class IP7_Trace + : public IP7C_Channel +{ +public: + typedef void* hModule; + + //////////////////////////////////////////////////////////////////////////// + //Set_Verbosity - function to set trace verbosity, traces with less priority + // will be rejected. You may set verbosity online from Baical + // server. See documentation for details. + virtual void Set_Verbosity(IP7_Trace::hModule i_hModule, + eP7Trace_Level i_eVerbosity + ) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Get_Verbosity - function to get trace verbosity. + // See documentation for details. + virtual eP7Trace_Level Get_Verbosity(IP7_Trace::hModule i_hModule) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Register_Thread - function used to specify name for current thread. Allows + // you to have nice trace message formatting on Baical side + // and in addition to ThreadId get Thread Name. + // Call the function from the newly created thread & call + // Unregister_Thread() right before exiting from thread + // body function. + //N.B.: If internally your application creates & destroys thousands of + // threads - usage of this functions is not good choice due to server + // overhead to store & manage this information - all threads info will + // be stored in RAM and may consume CPU to organize them in RB tree. + virtual tBOOL Register_Thread(const tXCHAR *i_pName, + tUINT32 i_dwThreadId + ) = 0; + virtual tBOOL Unregister_Thread(tUINT32 i_dwThreadId) = 0; + + + //////////////////////////////////////////////////////////////////////////// + //Register_Module - function is used register application module for using + // it by trace messages, if module with such name is + // already registered - existing handle will be returned + virtual tBOOL Register_Module(const tXCHAR *i_pName, + IP7_Trace::hModule *o_hModule + ) = 0; + + + //////////////////////////////////////////////////////////////////////////// + //Share - function to share current P7.Trace object in address space of the + // current process, to get shared instance use function + // P7_Get_Shared_Trace(tXCHAR *i_pName). + // See documentation for details. + virtual tBOOL Share(const tXCHAR *i_pName) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Trace - send trace message to Baical server. See documentation for details + //N.B.: USE THIS FUNCTION ONLY FROM C/C++ LANGUAGES ! if you want to use + // trace functionality from other languages please call Trace_Managed() + virtual tBOOL Trace(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR *i_pFormat, + ... + ) = 0; + + //////////////////////////////////////////////////////////////////////////// + //N.B: FUNCTION IS OBSOLETE, // + // Please use instead function Trace_Embedded(..., va_list*) // + //////////////////////////////////////////////////////////////////////////// + //Trace_Embedded - send trace message + //this function is a copy of Trace function, but it is dedicated to embedded + //usage (you already have function with variable arguments, but body of your + //function may be replaced by Trace_Embedded). + //See documentation for details. + virtual tBOOL Trace_Embedded(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat + ) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Trace_Embedded - send trace message + //this function is a copy of Trace function, but it is dedicated to embedded + //usage (you already have function with variable arguments, but body of your + //function may be replaced by Trace_Embedded). + //See documentation for details. + virtual tBOOL Trace_Embedded(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Trace_Managed - send trace message + //this function is intended for use by MANAGED languages like C#,python, etc + //See documentation for details. + virtual tBOOL Trace_Managed(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + const tXCHAR *i_pMessage + ) = 0; +}; + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Create_Trace - function create new instance of IP7_Trace object +//See documentation for details. +extern "C" P7_EXPORT IP7_Trace * __cdecl P7_Create_Trace(IP7_Client *i_pClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf = 0 + ); + + +//////////////////////////////////////////////////////////////////////////////// +//This functions allow you to get P7 trace instance if it was created by +//someone other inside current process. If no instance was registered inside +//current process - function will return NULL. Do not forget to call Release +//on interface when you finish your work. +//See documentation for details. +extern "C" P7_EXPORT IP7_Trace * __cdecl P7_Get_Shared_Trace(const tXCHAR *i_pName); + +#endif //P7_TRACE_H diff --git a/p7lib/Headers/P7_Version.h b/p7lib/Headers/P7_Version.h new file mode 100644 index 0000000..27a31b2 --- /dev/null +++ b/p7lib/Headers/P7_Version.h @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef P7_VERSION_H +#define P7_VERSION_H +//----------------------------------------- +#define P7_VERSION 00050006 +#define P7_VERSION_MAJOR 5 +#define P7_VERSION_MINOR 6 +//----------------------------------------- +#endif //P7_VERSION_H diff --git a/p7lib/License.txt b/p7lib/License.txt new file mode 100644 index 0000000..b0d2b1e --- /dev/null +++ b/p7lib/License.txt @@ -0,0 +1,57 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 3, 29 June 2007 + +Copyright © 2007 Free Software Foundation, Inc. + + Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. +0. Additional Definitions. + +As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. + +“The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. + +An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. + +A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. + +The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. + +The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. +1. Exception to Section 3 of the GNU GPL. + +You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. +2. Conveying Modified Versions. + +If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: +a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or +b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. +3. Object Code Incorporating Material from Library Header Files. + +The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: +a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. +b) Accompany the object code with a copy of the GNU GPL and this license document. +4. Combined Works. + +You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: +a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. +b) Accompany the Combined Work with a copy of the GNU GPL and this license document. +c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. +d) Do one of the following: +0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. +1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. +e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) +5. Combined Libraries. + +You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: +a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. +b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. +6. Revised Versions of the GNU Lesser General Public License. + +The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. \ No newline at end of file diff --git a/p7lib/Shared/AList.h b/p7lib/Shared/AList.h new file mode 100644 index 0000000..13131f4 --- /dev/null +++ b/p7lib/Shared/AList.h @@ -0,0 +1,826 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//****************************************************************************** +// This header file contains simple template lists * +// 1. List with customizable memory manager (CListBase) * +// 2. List with pooling of internal elements (CListPool) * +//****************************************************************************** +#ifndef ALIST_H +#define ALIST_H + +typedef void *pAList_Cell; + +//////////////////////////////////////////////////////////////////////////////// +//CListBase +template +class CListBase +{ +protected: + struct tCell + { + tData_Type m_pData; + tCell *m_pNext; + tCell *m_pPrev; + }; + + typedef tCell* pIndex_Cell; + + tCell *m_pFirst; + tCell *m_pLast; + + tUINT32 m_dwCount; + //HANDLE m_hLock_Mutex; + + pIndex_Cell *m_pIndex; + tBOOL m_bBrokenIndex; + tUINT32 m_dwIndexCount; + + tBOOL m_bInitialized; + +public: + //////////////////////////////////////////////////////////////////////////// + //CListBase::CListBase + CListBase() + { + m_bInitialized = TRUE; + m_pFirst = NULL; + m_pLast = NULL; + m_dwCount = 0; + m_pIndex = NULL; + m_bBrokenIndex = TRUE; + m_dwIndexCount = 0; + //m_hLock_Mutex = CreateMutex(NULL, FALSE, NULL); + + //if (NULL == m_hLock_Mutex) + //{ + // m_bInitialized = FALSE; + //} + }//CListBase::AList + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::~CListBase + virtual ~CListBase() + { + Index_Release(); + + //if (m_hLock_Mutex) + //{ + // CloseHandle(m_hLock_Mutex); + // m_hLock_Mutex = NULL; + //} + + if (m_dwCount) + { +#ifdef _DEBUG + #if defined(_WIN32) || defined(_WIN64) + OutputDebugStringW(L"Warning: List is not empty\n"); + #endif +#endif + } + }//CListBase::~CListBase + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_Initialized + inline tBOOL Get_Initialized() + { + return m_bInitialized; + }//CListBase::Get_Initialized + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Del + inline tBOOL Del(pAList_Cell i_pCell, tBOOL i_bFree_Data) + { + tCell *l_pCell = static_cast(i_pCell); + tBOOL l_bResult = TRUE; + + if (l_pCell) + { + l_bResult = Cell_Release(l_pCell, TRUE, i_bFree_Data); + } + + return l_bResult; + }//CListBase::Del + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Extract + inline tBOOL Extract(pAList_Cell i_pCell) + { + tCell *l_pCell = static_cast(i_pCell); + tBOOL l_bResult = TRUE; + + if (l_pCell) + { + l_bResult = Cell_Release(l_pCell, FALSE, FALSE); + l_pCell->m_pNext = NULL; + l_pCell->m_pPrev = NULL; + } + + return l_bResult; + }//CListBase::Extract + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Pull_First + inline tData_Type Pull_First() + { + tData_Type l_pReturn = m_pFirst->m_pData; + Cell_Release(m_pFirst, TRUE, FALSE); + return l_pReturn; + } + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Pull_Last + inline tData_Type Pull_Last() + { + tData_Type l_pReturn = m_pLast->m_pData; + Cell_Release(m_pLast, TRUE, FALSE); + return l_pReturn; + } + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Push_First + inline pAList_Cell Push_First(tData_Type i_pData) + { + return Add_After(NULL, i_pData); + } + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Push_Last + inline pAList_Cell Push_Last(tData_Type i_pData) + { + return Add_After(m_pLast, i_pData); + } + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Add_After + inline pAList_Cell Add_After(pAList_Cell i_pCell, tData_Type i_pData) + { + tCell *l_pNew_Cell = NULL; + tCell *l_pList_Cell = static_cast(i_pCell); + + l_pNew_Cell = Cell_Allocate(); + + if (l_pNew_Cell) + { + memset(l_pNew_Cell, 0, sizeof(tCell)); + l_pNew_Cell->m_pData = i_pData; + l_pNew_Cell->m_pNext = NULL; + l_pNew_Cell->m_pPrev = NULL; + + Put_After(l_pList_Cell, l_pNew_Cell); + } + + return static_cast(l_pNew_Cell); + }//CListBase::Add_After + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Put_After + inline tBOOL Put_After(pAList_Cell i_pList_Cell, pAList_Cell i_pExt_Cell) + { + tCell *l_pList_Cell = static_cast(i_pList_Cell); + tCell *l_pExt_Cell = static_cast(i_pExt_Cell); + tBOOL l_bResult = TRUE; + + if (NULL == l_pExt_Cell) + { + return FALSE; + } + + m_dwCount++; + + if (l_pList_Cell) + { + l_pExt_Cell->m_pNext = l_pList_Cell->m_pNext; + l_pExt_Cell->m_pPrev = l_pList_Cell; + if (l_pList_Cell->m_pNext) + { + l_pList_Cell->m_pNext->m_pPrev = l_pExt_Cell; + } + l_pList_Cell->m_pNext = l_pExt_Cell; + } + + + if ((NULL == l_pList_Cell) && (m_pFirst)) + { + m_pFirst->m_pPrev = l_pExt_Cell; + l_pExt_Cell->m_pNext = m_pFirst; + m_pFirst = l_pExt_Cell; + } + + if ((m_pLast) && (m_pLast == l_pList_Cell)) + { + m_pLast = l_pExt_Cell; + } + + if (!m_pFirst) + { + m_pFirst = l_pExt_Cell; + m_pLast = l_pExt_Cell; + } + + m_bBrokenIndex = TRUE; + + return l_bResult; + }//CListBase::Put_After + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_Prev + inline pAList_Cell Get_Prev(pAList_Cell i_pCell) + { + tCell *l_pCell = static_cast(i_pCell); + pAList_Cell l_pResult = NULL; + + if (l_pCell) + { + l_pResult = static_cast(l_pCell->m_pPrev); + } + else + { + l_pResult = static_cast(m_pLast); + } + + return l_pResult; + }//CListBase::Get_Prev + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_Next + inline pAList_Cell Get_Next(pAList_Cell i_pCell) + { + tCell *l_pCell = static_cast(i_pCell); + pAList_Cell l_pResult = NULL; + + if (l_pCell) + { + l_pResult = static_cast(l_pCell->m_pNext); + } + else + { + l_pResult = static_cast(m_pFirst); + } + + return l_pResult; + }//CListBase::Get_Next + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_Data + inline tData_Type Get_Data(pAList_Cell i_pCell) + { + tCell *l_pCell = static_cast(i_pCell); + tData_Type l_pResult = 0; + if (l_pCell) + { + l_pResult = l_pCell->m_pData; + } + + return l_pResult; + }//CListBase::Get_Data + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Set_Data + inline tBOOL Set_Data(pAList_Cell i_pCell, tBOOL i_bFree_Old_Data, tData_Type i_pData) + { + tCell *l_pCell = static_cast(i_pCell); + tData_Type l_pResult = NULL; + if (l_pCell) + { + if (i_bFree_Old_Data) + { + Data_Release(l_pCell->m_pData); + } + + l_pCell->m_pData = i_pData; + } + + return TRUE; + }//CListBase::Set_Data + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_ByIndex + inline pAList_Cell Get_ByIndex(tUINT32 i_dwIDX) + { + tCell *l_pReturn = NULL; + tUINT32 l_dwI; + + if (m_bBrokenIndex) + { + Index_Build(); + } + + if (i_dwIDX < m_dwCount) + { + if ( (FALSE == m_bBrokenIndex) + && (m_pIndex) + ) + { + l_pReturn = m_pIndex[i_dwIDX]; + } + else + { + l_pReturn = m_pFirst; + for (l_dwI = 0; l_dwI < i_dwIDX; l_dwI++) + { + if (l_pReturn) + { + l_pReturn = l_pReturn->m_pNext; + } + else + { + break; + } + } + } + } + + return l_pReturn; + }//CListBase::Get_ByIndex + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::operator[] + inline tData_Type operator[](tUINT32 i_dwIDX) + { + tCell *l_pReturn = static_cast(Get_ByIndex(i_dwIDX)); + + return (l_pReturn) ? l_pReturn->m_pData : NULL; + }//CListBase::operator[] + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Put_Data + inline tBOOL Put_Data(pAList_Cell i_pCell, tData_Type i_pData, tBOOL i_bFree_Old_Data) + { + tBOOL l_bResult = TRUE; + tCell *l_pCell = static_cast(i_pCell); + if (l_pCell) + { + if ( i_bFree_Old_Data ) + { + Data_Release(l_pCell->m_pData); + l_pCell->m_pData = NULL; + } + + l_pCell->m_pData = i_pData; + } + else + { + l_bResult = FALSE; + } + + + return l_bResult; + }//CListBase::Put_Data + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Lock + //void Lock() + //{ + // WaitForSingleObject(m_hLock_Mutex, INFINITE); + //}//CListBase::Lock + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::UnLock + //void UnLock() + //{ + // ReleaseMutex(m_hLock_Mutex); + //}//CListBase::UnLock + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Clear + inline void Clear(tBOOL i_bClearData) + { + while (NULL != m_pFirst) + { + if (TRUE != Cell_Release(m_pFirst, TRUE, i_bClearData)) + { + break; + } + } + }//CListBase::Clear + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_First + inline pAList_Cell Get_First() + { + return static_cast(m_pFirst); + }//CListBase::Get_First + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Get_Last + inline pAList_Cell Get_Last() + { + return static_cast(m_pLast); + }//CListBase::Get_Last + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Count + inline tUINT32 Count() + { + return m_dwCount; + }//CListBase::Count + +private: + //////////////////////////////////////////////////////////////////////////// + //CListBase::Cell_Release + inline tBOOL Cell_Release(tCell *i_pCell, tBOOL i_bFree_Cell, tBOOL i_bFree_Data) + { + tBOOL l_bResult = TRUE; + + if (NULL == i_pCell) + { + return FALSE; + } + + if ((NULL != i_pCell->m_pPrev) && (NULL != i_pCell->m_pNext)) + { + i_pCell->m_pPrev->m_pNext = i_pCell->m_pNext; + i_pCell->m_pNext->m_pPrev = i_pCell->m_pPrev; + } + else + { + l_bResult = FALSE; + + if (i_pCell == m_pFirst) + { + m_pFirst = i_pCell->m_pNext; + + if (m_pFirst != 0) + { + m_pFirst->m_pPrev = 0; + } + + l_bResult = TRUE; + } + + if (i_pCell == m_pLast) + { + m_pLast = i_pCell->m_pPrev; + if (m_pLast != 0) + { + m_pLast->m_pNext = 0; + } + + l_bResult = TRUE; + } + } + + if (TRUE == l_bResult) + { + if (i_bFree_Data) + { + Data_Release(i_pCell->m_pData); + i_pCell->m_pData = 0; + } + + if (i_bFree_Cell) + { + Cell_Free(i_pCell); + } + } + + m_bBrokenIndex = TRUE; + + m_dwCount--; + + return l_bResult; + }//CListBase::Cell_Release + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Index_Build + inline tBOOL Index_Build() + { + tBOOL l_bResult = TRUE; + + if ( (m_pIndex) && (m_dwCount > m_dwIndexCount) ) + { + Index_Release(); + } + + if (NULL == m_pIndex) + { + m_dwIndexCount = m_dwCount + 128; + m_pIndex = (pIndex_Cell*)this->MemAlloc(sizeof(pIndex_Cell) * m_dwIndexCount); + } + + if (NULL == m_pIndex) + { + l_bResult = FALSE; + m_dwIndexCount = 0; + } + + if (TRUE == l_bResult) + { + pAList_Cell l_pEl = NULL; + + memset(m_pIndex, 0, m_dwIndexCount * sizeof(pIndex_Cell)); + + pIndex_Cell *l_pIndexLocal = m_pIndex; + + while ((l_pEl = Get_Next(l_pEl)) != NULL) + { + *l_pIndexLocal = static_cast(l_pEl); + l_pIndexLocal ++; + } + + m_bBrokenIndex = FALSE; + } + + return l_bResult; + }//CListBase::Index_Build + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Index_Release + inline tBOOL Index_Release() + { + if (m_pIndex) + { + this->MemFree(m_pIndex); + m_pIndex = NULL; + } + + m_dwIndexCount = 0; + m_bBrokenIndex = TRUE; + return TRUE; + }//CListBase::Index_Release + +protected: + //////////////////////////////////////////////////////////////////////////// + //CListBase::Data_Release + // override this function in derived class to implement specific data + // destructor(structures as example) + virtual tBOOL Data_Release(tData_Type i_pData) = 0; + + //////////////////////////////////////////////////////////////////////////// + //CListBase::MemAlloc + //override this function in derived class to implement own memory allocation + //mechanism, it will be used everywhere in this class + virtual void *MemAlloc(size_t i_szSize) + { + return new tUINT8[i_szSize]; + }//CListBase::MemAlloc + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::MemFree + //override this function in derived class to implement own memory deallocation + //mechanism, it will be used everywhere in this class + virtual void MemFree(void * i_pMemory) + { + delete [] ((tUINT8*)i_pMemory); + }//CListBase::MemFree + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Cell_Allocate + virtual tCell *Cell_Allocate() + { + return (tCell*)this->MemAlloc(sizeof(tCell)); + }//Cell_Allocate + + + //////////////////////////////////////////////////////////////////////////// + //CListBase::Cell_Free + virtual void Cell_Free(tCell *i_pCell) + { + this->MemFree(i_pCell); + }//Cell_Free +}; + +//////////////////////////////////////////////////////////////////////////////// +//CAList +template +class CAList + : public CListBase +{ +protected: + //////////////////////////////////////////////////////////////////////////// + //CListBase::Data_Release + // override this function in derived class to implement specific data + // destructor(structures as example) + virtual tBOOL Data_Release(tData_Type i_pData) + { + if (NULL == i_pData) + { + return FALSE; + } + + delete i_pData; + return TRUE; + }//CListBase::Data_Release +}; + + +//////////////////////////////////////////////////////////////////////////////// +//This list has pool for list's cells, this technology speedup allocation and +//deallocation of new list's elements (6-10 times). +//List intended for situation when you has very intensive adding & deleting +//process, but it will use a lot of memory if you will add 1 million items and +//then delete 999 thousands, after that all 999 thousands internal list cells +//will be stored in internal pool, for the time being mechanism of pool packing +//is not developed. +//N.B.: be careful with list, use it only when you absolutely sure in what are +// you doing. +template +class CListPool: + public CListBase +{ +private: + #define TCELL typename CListBase::tCell + + struct tPool_Segment + { + TCELL *m_pCells; + tUINT32 m_dwCount; + tPool_Segment *m_pNext; + }; + + tPool_Segment *m_pPool_First; + TCELL *m_pPool_Cell_First; + + //count of cell allocated for every pool segment + tUINT32 m_dwPool_Size; +public: + //////////////////////////////////////////////////////////////////////////// + //CListPool::CListPool + CListPool(tUINT32 i_dwPool_Size = 128) + : CListBase() + , m_dwPool_Size(i_dwPool_Size) + { + m_pPool_First = NULL; + m_pPool_Cell_First = NULL; + }//CListPool::CListPool + + + //////////////////////////////////////////////////////////////////////////// + //CListPool::~CListPool + virtual ~CListPool() + { + tPool_Segment *l_pPool_Tmp = NULL; + while (m_pPool_First) + { + l_pPool_Tmp = m_pPool_First; + m_pPool_First = m_pPool_First->m_pNext; + + Free_Pool_Segment(l_pPool_Tmp); + } + }//CListPool::~CListPool + +private: + //////////////////////////////////////////////////////////////////////////// + //CListPool::Create_Pool_Segment + inline tBOOL Create_Pool_Segment() + { + tBOOL l_bReturn = FALSE; + + tPool_Segment *l_pPool = (tPool_Segment*)CListBase::MemAlloc(sizeof(tPool_Segment)); + + if (l_pPool) + { + memset(l_pPool, 0, sizeof(tPool_Segment)); + l_pPool->m_dwCount = m_dwPool_Size; + l_pPool->m_pCells = (TCELL*)this->MemAlloc(sizeof(TCELL) * l_pPool->m_dwCount); + + if (l_pPool->m_pCells) + { + TCELL *l_pCell = NULL; + + memset(l_pPool->m_pCells, + 0, + sizeof(tPool_Segment) * l_pPool->m_dwCount + ); + + l_pCell = l_pPool->m_pCells; + + for (tUINT32 l_dwIDX = 1; l_dwIDX < l_pPool->m_dwCount; l_dwIDX++) + { + l_pCell->m_pNext = (l_pCell + 1); + l_pCell ++; + } + + l_bReturn = TRUE; + l_pPool->m_pNext = m_pPool_First; + m_pPool_First = l_pPool; + l_pCell->m_pNext = m_pPool_Cell_First; + m_pPool_Cell_First = l_pPool->m_pCells; + } + } + + if (FALSE == l_bReturn) + { + Free_Pool_Segment(l_pPool); + } + + return l_bReturn; + }//CListPool::Create_Pool_Segment + + + //////////////////////////////////////////////////////////////////////////// + //CListPool::Free_Pool_Segment + inline void Free_Pool_Segment(tPool_Segment *io_pPool) + { + if (io_pPool) + { + if (io_pPool->m_pCells) + { + this->MemFree(io_pPool->m_pCells); + io_pPool->m_pCells = NULL; + } + this->MemFree(io_pPool); + } + }//CListPool::Free_Pool_Segment + +protected: + //////////////////////////////////////////////////////////////////////////// + //CListPool::Cell_Allocate + virtual TCELL *Cell_Allocate() + { + TCELL *l_pReturn = NULL; + if (NULL == m_pPool_Cell_First) + { + Create_Pool_Segment(); + } + + l_pReturn = m_pPool_Cell_First; + + if (m_pPool_Cell_First) + { + m_pPool_Cell_First = m_pPool_Cell_First->m_pNext; + } + + return l_pReturn; + }//CListPool::Cell_Allocate + + + //////////////////////////////////////////////////////////////////////////// + //CListPool::Cell_Free + virtual void Cell_Free(TCELL *i_pCell) + { + memset(i_pCell, 0, sizeof(TCELL)); + i_pCell->m_pNext = m_pPool_Cell_First; + m_pPool_Cell_First = i_pCell; + }//CListPool::Cell_Free +}; + + +//////////////////////////////////////////////////////////////////////////////// +//CBList +template +class CBList + : public CListPool +{ +public: + //////////////////////////////////////////////////////////////////////////// + //CListPool::CListPool + CBList(tUINT32 i_dwPool_Size = 128) + : CListPool(i_dwPool_Size) + { + }//CBList::CBList + +protected: + //////////////////////////////////////////////////////////////////////////// + //CListBase::Data_Release + // override this function in derived class to implement specific data + // destructor(structures as example) + virtual tBOOL Data_Release(tData_Type i_pData) + { + if (NULL == i_pData) + { + return FALSE; + } + + delete i_pData; + return TRUE; + }//CListBase::Data_Release +}; + +#endif //ALIST_H diff --git a/p7lib/Shared/CMakeLists.txt b/p7lib/Shared/CMakeLists.txt new file mode 100644 index 0000000..6673920 --- /dev/null +++ b/p7lib/Shared/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +set(PATH_SHARED ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "") +set(PATH_SHARED_CRYPTO ${CMAKE_CURRENT_SOURCE_DIR}/Crypto CACHE INTERNAL "") +set(PATH_SHARED_XML ${CMAKE_CURRENT_SOURCE_DIR}/XML CACHE INTERNAL "") + +if(WIN32) + set(PATH_SHARED_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/Platforms/Windows_x86 CACHE INTERNAL "") +else() + set(PATH_SHARED_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR}/Platforms/Linux_x86 CACHE INTERNAL "") +endif() diff --git a/p7lib/Shared/CRC32.h b/p7lib/Shared/CRC32.h new file mode 100644 index 0000000..547e80e --- /dev/null +++ b/p7lib/Shared/CRC32.h @@ -0,0 +1,122 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//****************************************************************************** +// This header file provide CRC32 functions * +//****************************************************************************** +#ifndef CRC32_H +#define CRC32_H + +#include +#include "GTypes.h" + +static tUINT32 g_pCRC32_Table[] = +{ + 0x00000000L, 0x77073096L, 0xee0e612cL, + 0x990951baL, 0x076dc419L, 0x706af48fL, + 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, + 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, + 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, + 0xf3b97148L, 0x84be41deL, 0x1adad47dL, + 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, + 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, + 0x4c69105eL, 0xd56041e4L, 0xa2677172L, + 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, + 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, + 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, + 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, + 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, + 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, + 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, + 0x98d220bcL, 0xefd5102aL, 0x71b18589L, + 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, + 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, + 0x1c6c6162L, 0x856530d8L, 0xf262004eL, + 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, + 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, + 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, + 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, + 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, + 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, + 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, + 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, + 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, + 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, + 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, + 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, + 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, + 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, + 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, + 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, + 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, + 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, + 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, + 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, + 0x41047a60L, 0xdf60efc3L, 0xa867df55L, + 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, + 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, + 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, + 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, + 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, + 0x72076785L, 0x05005713L, 0x95bf4a82L, + 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, + 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, + 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, + 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, + 0x11010b5cL, 0x8f659effL, 0xf862ae69L, + 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, + 0xa7672661L, 0xd06016f7L, 0x4969474dL, + 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, + 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, + 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, + 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, + 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, + 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, + 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +static tUINT32 *g_ppCRC32_Table = &g_pCRC32_Table[0]; + +#include "PCRC32.h" + +#endif //CRC32_H diff --git a/p7lib/Shared/DnsResolver.h b/p7lib/Shared/DnsResolver.h new file mode 100644 index 0000000..e9ef474 --- /dev/null +++ b/p7lib/Shared/DnsResolver.h @@ -0,0 +1,519 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef DNS_RESOLVER_H +#define DNS_RESOLVER_H + +#include "AList.h" +#include "RBTree.h" +#include "PSocket.h" +#include "PAtomic.h" +#include "PLock.h" +#include "IMEvent.h" +#include "PMEvent.h" +#include "PThreadShell.h" +#include "PTime.h" + +#if !defined(NI_MAXHOST) + #define NI_MAXHOST 1025 /* Max size of a fully-qualified domain name */ +#endif + +#define DNS_RESOLVE_TIME_OUT_MIN (50) +#define DNS_RESOLVE_TIME_OUT_MAX (500) + +#define DNS_RESOLVER_EXIT_EVENT (MEVENT_SIGNAL_0) +#define DNS_RESOLVER_EVENT (MEVENT_SIGNAL_0 + 1) + +#define DNS_NAME_EVENT (MEVENT_SIGNAL_0) + + +//////////////////////////////////////////////////////////////////////////////// +//CDNS_Item +class CDNS_Item +{ + tXCHAR *m_pName; //host name + tXCHAR m_pIP[96]; + size_t m_szName_Max; //host name max length + size_t m_szName; //host name current length + sockaddr_storage m_sSAS; //host Socket address V4/V6 + CMEvent m_cEvent; +public: + //////////////////////////////////////////////////////////////////////////// + //CDNS_Item + CDNS_Item(sockaddr *i_pSA) + : m_pName(NULL) + , m_szName_Max(0) + , m_szName(0) + { + if (AF_INET == i_pSA->sa_family) + { + memcpy(&m_sSAS, i_pSA, sizeof(sockaddr_in)); + ((sockaddr_in*)&m_sSAS)->sin_port = 0; + } + else if (AF_INET6 == i_pSA->sa_family) + { + memcpy(&m_sSAS, i_pSA, sizeof(sockaddr_in6)); + ((sockaddr_in6*)&m_sSAS)->sin6_port = 0; + } + + if (Print_SAddr((sockaddr*)&m_sSAS, m_pIP, LENGTH(m_pIP))) + { + size_t l_szIP = PStrLen(m_pIP); + + for (size_t l_szI = 0; l_szI < l_szIP; l_szI ++) + { + if (TM(':') == m_pIP[l_szI]) + { + m_pIP[l_szI] = TM('x'); + } + } + } + else + { + PStrCpy(m_pIP, LENGTH(m_pIP), TM("Unknown")); + } + + m_cEvent.Init(1, EMEVENT_SINGLE_AUTO); + }//CDNS_Item + + //////////////////////////////////////////////////////////////////////////// + //~CDNS_Item + ~CDNS_Item() + { + if (m_pName) + { + delete [] m_pName; + m_pName = NULL; + } + } + + //////////////////////////////////////////////////////////////////////////// + //Get_SA + const sockaddr *Get_SA() + { + return (sockaddr*)&m_sSAS; + }//Get_SA + + + //////////////////////////////////////////////////////////////////////////// + //Get_Event + CMEvent *Get_Event() + { + return &m_cEvent; + }//Get_Event + + //////////////////////////////////////////////////////////////////////////// + //Update + tBOOL Update(tXCHAR *i_pName) + { + tXCHAR *l_pName = (i_pName) ? i_pName : m_pIP; + size_t l_szName = PStrLen(l_pName); + + if (l_szName > m_szName_Max) + { + if (m_pName) + { + delete [] m_pName; + m_pName = NULL; + } + + m_szName_Max = (l_szName + 1 + 15) & (~15UL); + m_pName = new tXCHAR[m_szName_Max]; + } + + if (NULL != m_pName) + { + m_szName = l_szName; + PStrCpy(m_pName, m_szName_Max, l_pName); + } + else + { + m_szName = 0; + m_szName_Max = 0; + } + + return (m_pName) ? TRUE : FALSE; + }//Update + + + //////////////////////////////////////////////////////////////////////////// + //Get_Name() + tBOOL Get_Name(tXCHAR *o_pName, size_t i_szLength_Max) + { + if ( (o_pName) + && (1 < i_szLength_Max) + ) + { + if (m_szName >= i_szLength_Max) + { + PStrNCpy(o_pName, i_szLength_Max, m_pName, i_szLength_Max - 1); + } + else + { + PStrCpy(o_pName, i_szLength_Max, m_pName); + } + + return TRUE; + } + + return FALSE; + }//Get_Name() + + //////////////////////////////////////////////////////////////////////////// + //Is_Greater -> (m_sSA > i_pSA) == TRUE + tBOOL Is_Greater(sockaddr *i_pSA) + { + if (m_sSAS.ss_family > i_pSA->sa_family) + { + return TRUE; + } + else if (m_sSAS.ss_family < i_pSA->sa_family) + { + return FALSE; + } + + if (AF_INET == i_pSA->sa_family) + { + return (((sockaddr_in*)&m_sSAS)->sin_addr.s_addr > ((sockaddr_in*)i_pSA)->sin_addr.s_addr); + } + else if (AF_INET6 == i_pSA->sa_family) + { + return (0 < memcmp(((sockaddr_in6*)&m_sSAS)->sin6_addr.s6_addr, + ((sockaddr_in6*)i_pSA)->sin6_addr.s6_addr, + sizeof(in6_addr) + ) + ); + } + + return FALSE; + }//Is_Greater + + //////////////////////////////////////////////////////////////////////////// + //Is_Equal + tBOOL Is_Equal(sockaddr *i_pSA) + { + if (m_sSAS.ss_family == i_pSA->sa_family) + { + if (AF_INET == i_pSA->sa_family) + { + return (((sockaddr_in*)&m_sSAS)->sin_addr.s_addr == ((sockaddr_in*)i_pSA)->sin_addr.s_addr); + } + else if (AF_INET6 == i_pSA->sa_family) + { + return (0 == memcmp(((sockaddr_in6*)&m_sSAS)->sin6_addr.s6_addr, + ((sockaddr_in6*)i_pSA)->sin6_addr.s6_addr, + sizeof(in6_addr) + ) + ); + } + } + + return FALSE; + }//Is_Equal +}; + + +//////////////////////////////////////////////////////////////////////////////// +//CDNS_Resolver +class CDNS_Resolver: + public CRBTree +{ + volatile tINT32 m_lTimeOut; + tLOCK m_sCS; + CThShell::tTHREAD m_hThread; + tBOOL m_bIsThread; + CMEvent m_cEvent; + CBList m_cRecords; + CBList m_cResolving; +public: + //////////////////////////////////////////////////////////////////////////// + //CDNS_Resolver() + CDNS_Resolver() + : CRBTree(32, FALSE) + , m_lTimeOut(DNS_RESOLVE_TIME_OUT_MAX) + , m_bIsThread(FALSE) + , m_cRecords(32) + { + LOCK_CREATE(m_sCS); + + m_cEvent.Init(2, EMEVENT_SINGLE_AUTO, EMEVENT_MULTI); + + if (CThShell::Create(&Static_Routine, this, &m_hThread, TM("DNSR"))) + { + m_bIsThread = TRUE; + } + + }//~CDNS_Resolver() + + //////////////////////////////////////////////////////////////////////////// + //~CDNS_Resolver() + ~CDNS_Resolver() + { + if (m_bIsThread) + { + m_cEvent.Set(DNS_RESOLVER_EXIT_EVENT); + if (TRUE == CThShell::Close(m_hThread, 90000)) + { + m_hThread = 0;//NULL; + m_bIsThread = FALSE; + } + } + + m_cResolving.Clear(FALSE); + m_cRecords.Clear(TRUE); + + LOCK_DESTROY(m_sCS); + }//~CDNS_Resolver() + + //////////////////////////////////////////////////////////////////////////// + //Get_Name() + tBOOL Get_Name(sockaddr *i_pKey, tXCHAR *o_pName, size_t i_szName, tBOOL *o_pNew) + { + CDNS_Item *l_pRec = NULL; + tBOOL l_bAdd = FALSE; + + if ( (NULL == i_pKey) + || ( (AF_INET != i_pKey->sa_family) + && (AF_INET6 != i_pKey->sa_family) + ) + || (NULL == o_pName) + || (16 > i_szName) + ) + { + return FALSE; + } + + LOCK_ENTER(m_sCS); + l_pRec = this->Find(i_pKey); + if (NULL == l_pRec) + { + l_pRec = new CDNS_Item(i_pKey); + if (l_pRec) + { + this->Push(l_pRec, i_pKey); + m_cRecords.Add_After(m_cRecords.Get_Last(), l_pRec); + l_pRec->Update(NULL); + l_bAdd = TRUE; + } + + if (o_pNew) + { + *o_pNew = 1; + } + } + LOCK_EXIT(m_sCS); + + if (l_bAdd) + { + LOCK_ENTER(m_sCS); + m_cResolving.Add_After(m_cResolving.Get_Last(), l_pRec); + m_cEvent.Set(DNS_RESOLVER_EVENT); + LOCK_EXIT(m_sCS); + + l_pRec->Get_Event()->Wait((tUINT32)m_lTimeOut); + }//if (NULL == l_pRec) + + LOCK_ENTER(m_sCS); + if (l_pRec) + { + l_pRec->Get_Name(o_pName, i_szName); + } + LOCK_EXIT(m_sCS); + + return (NULL != l_pRec); + }//Get_Name() + +protected: + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(sockaddr *i_pKey, CDNS_Item *i_pData) + { + return i_pData->Is_Greater(i_pKey); + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(sockaddr *i_pKey, CDNS_Item *i_pData) + { + return i_pData->Is_Equal(i_pKey); + } + +private: + //////////////////////////////////////////////////////////////////////////// + //Routine_Static + static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_Routine(void *i_pContext) + { + CDNS_Resolver * l_pRoutine = (CDNS_Resolver *)i_pContext; + if (l_pRoutine) + { + l_pRoutine->Routine(); + } + + CThShell::Cleanup(); + return THSHELL_RET_OK; + } + + //////////////////////////////////////////////////////////////////////////// + //Routine + void Routine() + { + tXCHAR l_pName[NI_MAXHOST]; + tBOOL l_bExit = FALSE; + pAList_Cell l_pEl = NULL; + CDNS_Item *l_pRec = NULL; + tUINT32 l_dwWFMOR = 0; + tINT32 l_lWaitMax = -1; + tUINT32 l_dwTick = 0; + + while (FALSE == l_bExit) + { + l_dwWFMOR = m_cEvent.Wait(1000); + + if (DNS_RESOLVER_EXIT_EVENT == l_dwWFMOR) + { + l_bExit = TRUE; + } + else if (DNS_RESOLVER_EVENT == l_dwWFMOR) + { + LOCK_ENTER(m_sCS); + l_pRec = m_cResolving.Get_Data(m_cResolving.Get_First()); + m_cResolving.Del(m_cResolving.Get_First(), FALSE); + LOCK_EXIT(m_sCS); + + if (l_pRec) + { + l_dwTick = GetTickCount(); + if (Resolve_SA(l_pRec->Get_SA(), l_pName, LENGTH(l_pName))) + { + l_dwTick = CTicks::Difference(GetTickCount(), l_dwTick); + LOCK_ENTER(m_sCS); + l_pRec->Update(l_pName); + LOCK_EXIT(m_sCS); + } + else + { + l_dwTick = 0; + + LOCK_ENTER(m_sCS); + l_pRec->Update(NULL); + LOCK_EXIT(m_sCS); + } + l_pRec->Get_Event()->Set(DNS_NAME_EVENT); + } + + //Update waiting timeout based on maximum waiting of response + //from DNS server + if ((tINT32)l_dwTick > l_lWaitMax) + { + //set timeout with max limit of DNS_RESOLVE_TIME_OUT + if (l_dwTick > DNS_RESOLVE_TIME_OUT_MAX) + { + l_lWaitMax = DNS_RESOLVE_TIME_OUT_MAX; + } + else if (l_dwTick < DNS_RESOLVE_TIME_OUT_MIN) + { + l_lWaitMax = DNS_RESOLVE_TIME_OUT_MIN; + } + else + { + l_lWaitMax = (tINT32)l_dwTick; + } + + if (l_lWaitMax != m_lTimeOut) + { + ATOMIC_SET(&m_lTimeOut, l_lWaitMax); + } + } + } + else if (MEVENT_TIME_OUT == l_dwWFMOR) + { + LOCK_ENTER(m_sCS); + l_pEl = m_cRecords.Get_Next(l_pEl); + l_pRec = m_cRecords.Get_Data(l_pEl); + LOCK_EXIT(m_sCS); + + if (l_pRec) + { + if (Resolve_SA(l_pRec->Get_SA(), l_pName, LENGTH(l_pName))) + { + LOCK_ENTER(m_sCS); + l_pRec->Update(l_pName); + LOCK_EXIT(m_sCS); + } + else + { + LOCK_ENTER(m_sCS); + l_pRec->Update(NULL); + LOCK_EXIT(m_sCS); + } + } + } + } + }//Routine + + //////////////////////////////////////////////////////////////////////////// + //Resolve_SA + tBOOL Resolve_SA(const sockaddr *i_pSA, tXCHAR *o_pName, tUINT32 i_dwLength) + { + tUINT32 l_dwIP_Size = 0; + tBOOL l_bReturn = FALSE; + + if (NULL == i_pSA) + { + return l_bReturn; + } + + + if (AF_INET == i_pSA->sa_family) + { + l_dwIP_Size = sizeof(sockaddr_in); + } + else if (AF_INET6 == i_pSA->sa_family) + { + l_dwIP_Size = sizeof(sockaddr_in6); + } + + #ifdef UTF8_ENCODING + int l_iRes = getnameinfo(i_pSA, l_dwIP_Size, + o_pName, i_dwLength, + NULL, 0, + NI_NAMEREQD + ); + #else + int l_iRes = GetNameInfoW(i_pSA, l_dwIP_Size, + o_pName, i_dwLength, + NULL, 0, + NI_NAMEREQD + ); + #endif + + + if (0 == l_iRes) + { + l_bReturn = TRUE; + } + + return l_bReturn; + }//Resolve_SA +};//CDNS_Resolver + +#endif //DNS_RESOLVER_H \ No newline at end of file diff --git a/p7lib/Shared/IConsole.h b/p7lib/Shared/IConsole.h new file mode 100644 index 0000000..c97c4e7 --- /dev/null +++ b/p7lib/Shared/IConsole.h @@ -0,0 +1,929 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef ICONSOLE_H +#define ICONSOLE_H + +#define CON_RIGHT_ALT_PRESSED 0x0001 // the right alt key is pressed. +#define CON_LEFT_ALT_PRESSED 0x0002 // the left alt key is pressed. +#define CON_RIGHT_CTRL_PRESSED 0x0004 // the right ctrl key is pressed. +#define CON_LEFT_CTRL_PRESSED 0x0008 // the left ctrl key is pressed. +#define CON_SHIFT_PRESSED 0x0010 // the shift key is pressed. +#define CON_NUMLOCK_ON 0x0020 // the numlock light is on. +#define CON_SCROLLLOCK_ON 0x0040 // the scrolllock light is on. +#define CON_CAPSLOCK_ON 0x0080 // the capslock light is on. +#define CON_ENHANCED_KEY 0x0100 // the key is enhanced. + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class IConsole +{ +public: + enum eColor + { + eBlack = 0, + eBlue, + eGreen, + eCyan, + eRed, + eMagenta, + eBrown, + eLightGray, + eDarkGray, + eLightBlue, + eLightGreen, + eLightCyan, + eLightRed, + eLightMagenta, + eYellow, + eWhite, + eColorsMax + }; + + enum eEvent + { + eSize = 0, + eMouse, + eKey, + eFocus, + eEventsMax + }; + + enum eKey + { + eKeyEsc = 27, + eKeyEnter = 13, + eKeySpace = 32, + + eKeyExtra = 0x100, + eKeyArrowLeft, + eKeyArrowRight, + eKeyArrowDown, + eKeyArrowUp, + eKeyPageUp, + eKeyPageDown, + eKeyHome, + eKeyEnd, + eKeyF1, + eKeyF2, + eKeyF3, + eKeyF4, + eKeyF5, + eKeyF6, + eKeyF7, + eKeyF8, + eKeyF9, + eKeyF10, + eKeyF11, + eKeyF12, + eKeyDel, + eKeyInsert, + eKeyTab, + eKeyBackSpace, + + eKeyMax + }; + + struct sSize + { + tUINT32 uW; + tUINT32 uH; + }; + + struct sMouse + { + tUINT32 uX; + tUINT32 uY; + tUINT32 uButton; + }; + + struct sKey + { + tBOOL bDown; + tUINT16 wKey; + tUINT16 wCount; + tUINT32 uControls; + }; + + struct sFocus + { + tBOOL bFocus; + }; + + struct sInput + { + IConsole::eEvent eEvent; + union + { + sSize stSize; + sMouse stMouse; + sKey stKey; + sFocus stFocus; + }; + }; + + + + virtual tBOOL SetCursor(tUINT32 i_uX, tUINT32 i_uY) = 0; + virtual tUINT32 GetCursorX() = 0; + virtual tUINT32 GetCursorY() = 0; + virtual tUINT32 GetWidth() = 0; + virtual tUINT32 GetHeight() = 0; + virtual tBOOL SetTextAttr(IConsole::eColor i_eFg, IConsole::eColor i_eBg) = 0; + virtual tBOOL GetInput(IConsole::sInput &o_rInput) = 0; + virtual tBOOL Clear() = 0; + virtual tBOOL Clear(tUINT32 i_uX, tUINT32 i_uY, tUINT32 i_uW, tUINT32 i_uH, IConsole::eColor i_eBg) = 0; + virtual size_t WriteTextB(const tXCHAR *i_pText, size_t i_szText) = 0; + virtual size_t WriteTextB(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + tXCHAR *i_pText, + size_t i_szText, + size_t i_szTextMax + ) = 0; + + virtual size_t WriteTextO(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + const tXCHAR *i_pFormat, + ... + ) + { + va_list l_pVA; + size_t l_szReturn = 0; + + va_start(l_pVA, i_pFormat); + l_szReturn = WriteTextF(i_eFg, i_eBg, i_szLenMin, i_szLenMax, i_szOffset, i_pFormat, l_pVA); + va_end(l_pVA); + return l_szReturn; + } + + virtual size_t WriteText(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + const tXCHAR *i_pFormat, + ... + ) + { + va_list l_pVA; + size_t l_szReturn = 0; + + va_start(l_pVA, i_pFormat); + l_szReturn = WriteTextF(i_eFg, i_eBg, i_szLenMin, i_szLenMax, 0, i_pFormat, l_pVA); + va_end(l_pVA); + return l_szReturn; + } + + + virtual size_t WriteTextF(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + const tXCHAR *i_pFormat, + va_list i_pVA + ) = 0; + + virtual tBOOL Present() = 0; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CConsoleWnd +{ + struct stHelp + { + tXCHAR *pString; + IConsole::eColor eBgColor; + IConsole::eColor eFgColor; + + stHelp(const tXCHAR *i_pString, IConsole::eColor i_eBgColor, IConsole::eColor i_eFgColor) + { + pString = PStrDub(i_pString); + eBgColor = i_eBgColor; + eFgColor = i_eFgColor; + } + + ~stHelp() + { + if (pString) + { + free(pString); + pString = NULL; + } + } + }; + +public: + struct stColumn + { + tUINT32 uId; + tBOOL bVisible; + tXCHAR *pCaption; + size_t szCaption; + + stColumn(tUINT32 i_uId, tBOOL i_bVisible, const tXCHAR *i_pCaption) + : pCaption(NULL) + { + uId = i_uId; + bVisible = i_bVisible; + SetCaption(i_pCaption); + } + + ~stColumn() + { + if (pCaption) + { + PStrFreeDub(pCaption); + pCaption = NULL; + } + uId = 0; + bVisible = FALSE; + szCaption = 0; + } + + void SetCaption(const tXCHAR *i_pCaption) + { + if (pCaption) + { + PStrFreeDub(pCaption); + } + + pCaption = PStrDub(i_pCaption); + szCaption = PStrLen(pCaption); + } + }; + +protected: + tUINT32 m_uX; + tUINT32 m_uY; + tUINT32 m_uW; + tUINT32 m_uH; + size_t m_szLinesPerItem; + size_t m_szItemsPerWnd; + tUINT64 m_qwItemsCount; + IConsole *m_pConsole; + IConsole::eColor m_eWindowBgColor; + + IConsole::eColor m_eItemBgColor; + IConsole::eColor m_eItemFgColor; + + IConsole::eColor m_eItemSlFgColor; + IConsole::eColor m_eItemSlBgColor; + + IConsole::eColor m_eItemClFgColor; + IConsole::eColor m_eItemClBgColor; + + tBOOL m_bError; + tXCHAR *m_pCaption; + size_t m_szOffsetX; + size_t m_szOffsetY; + tUINT64 m_qwOffsetWnd; + tBOOL m_bHelp; + CBList m_cHelp; + CBListm_cColumns; + tBOOL m_bColumns; + tBOOL m_bUpdateColumns; + tXCHAR *m_pColumnsText; + size_t m_szColumnsTextMax; + size_t m_szColumnsText; + +public: + struct sCfg + { + tUINT32 uX; + tUINT32 uY; + tUINT32 uW; + tUINT32 uH; + size_t uLinesPerItem; + size_t szItemsCount; + IConsole *pConsole; + IConsole::eColor eWindowBgColor; + IConsole::eColor eItemBgColor; + IConsole::eColor eItemFgColor; + IConsole::eColor eItemSlFgColor; + IConsole::eColor eItemSlBgColor; + IConsole::eColor eItemClFgColor; + IConsole::eColor eItemClBgColor; + const tXCHAR *pCaption; + }; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + CConsoleWnd() + : m_uX(0) + , m_uY(0) + , m_uW(0) + , m_uH(0) + , m_szLinesPerItem(0) + , m_szItemsPerWnd(0) + , m_qwItemsCount(0ull) + , m_pConsole(NULL) + , m_eWindowBgColor(IConsole::eBlack) + , m_eItemBgColor(IConsole::eBlack) + , m_eItemFgColor(IConsole::eGreen) + , m_eItemSlFgColor(IConsole::eBlue) + , m_eItemSlBgColor(IConsole::eBlack) + , m_eItemClFgColor(IConsole::eWhite) + , m_eItemClBgColor(IConsole::eDarkGray) + , m_bError(FALSE) + , m_pCaption(NULL) + , m_szOffsetX(0) + , m_szOffsetY(0) + , m_qwOffsetWnd(0) + , m_bHelp(FALSE) + , m_bColumns(FALSE) + , m_bUpdateColumns(FALSE) + , m_pColumnsText(NULL) + , m_szColumnsTextMax(0) + , m_szColumnsText(0) + { + CConsoleWnd::PushHelpString(TM(" Navigation keys mapping:"), IConsole::eBlue, IConsole::eWhite); + CConsoleWnd::PushHelpString(TM(" * Arrow Up, Down, Page Up, Page down - move cursor"), IConsole::eBlack, IConsole::eGreen); + CConsoleWnd::PushHelpString(TM(" * Arrow Left, Right - horizontal scroll"), IConsole::eBlack, IConsole::eGreen); + CConsoleWnd::PushHelpString(TM(" * Home - goto top"), IConsole::eBlack, IConsole::eGreen); + CConsoleWnd::PushHelpString(TM(" * End - goto bottom"), IConsole::eBlack, IConsole::eGreen); + CConsoleWnd::PushHelpString(TM(" * Esc - exit to upper level or quit"), IConsole::eBlack, IConsole::eGreen); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual tBOOL Init(const CConsoleWnd::sCfg &i_rConfig) + { + m_pConsole = i_rConfig.pConsole; + m_eWindowBgColor = i_rConfig.eWindowBgColor; + m_eItemBgColor = i_rConfig.eItemBgColor; + m_eItemFgColor = i_rConfig.eItemFgColor; + m_eItemSlFgColor = i_rConfig.eItemSlFgColor; + m_eItemSlBgColor = i_rConfig.eItemSlBgColor; + m_eItemClFgColor = i_rConfig.eItemClFgColor; + m_eItemClBgColor = i_rConfig.eItemClBgColor; + m_szLinesPerItem = i_rConfig.uLinesPerItem; + m_qwItemsCount = i_rConfig.szItemsCount; + + SetCaption(i_rConfig.pCaption); + + m_pConsole->SetCursor(i_rConfig.uX, i_rConfig.uY); + m_pConsole->Clear(i_rConfig.uX, i_rConfig.uY, i_rConfig.uW, i_rConfig.uH, m_eWindowBgColor); + + return Resize(i_rConfig.uX, i_rConfig.uY, i_rConfig.uW, i_rConfig.uH); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetContext(void *i_pContext) + { + UNUSED_ARG(i_pContext); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~CConsoleWnd() + { + m_cHelp.Clear(TRUE); + m_cColumns.Clear(TRUE); + + if (m_pCaption) + { + PStrFreeDub(m_pCaption); + m_pCaption = NULL; + } + + if (m_pColumnsText) + { + free(m_pColumnsText); + m_pColumnsText = NULL; + } + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetCaption(const tXCHAR *i_pCaption) + { + if (m_pCaption) + { + PStrFreeDub(m_pCaption); + m_pCaption = NULL; + } + + m_pCaption = i_pCaption ? PStrDub(i_pCaption) : PStrDub(TM("?")); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void PushHelpString(const tXCHAR *i_pString, IConsole::eColor i_eBgColor, IConsole::eColor i_eFgColor) + { + if (i_pString) + { + m_cHelp.Add_After(m_cHelp.Get_Last(), new stHelp(i_pString, i_eBgColor, i_eFgColor)); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void PushColumn(tUINT32 i_uId, tBOOL i_bVisible, const tXCHAR *i_pCaption) + { + if (i_pCaption) + { + m_cColumns.Add_After(m_cColumns.Get_Last(), new stColumn(i_uId, i_bVisible, i_pCaption)); + m_bUpdateColumns = TRUE; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void EnableColumns(tBOOL i_bEnable) + { + m_bUpdateColumns = TRUE; + m_bColumns = i_bEnable; + UpdateItemsPerWindow(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual CConsoleWnd::stColumn *GetColumn(tUINT32 i_uIndex) + { + return m_cColumns[i_uIndex]; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void EnableColumn(tUINT32 i_uIndex, tBOOL i_bEnable) + { + stColumn *l_pCol = m_cColumns[i_uIndex]; + + if (!l_pCol) + { + return; + } + + l_pCol->bVisible = i_bEnable; + m_bUpdateColumns = TRUE; + + if (m_bColumns) + { + Redraw(); + } + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetColumnCaption(tUINT32 i_uIndex, const tXCHAR *i_pCation) + { + stColumn *l_pCol = m_cColumns[i_uIndex]; + + if (!l_pCol) + { + return; + } + + l_pCol->SetCaption(i_pCation); + m_bUpdateColumns = TRUE; + + if (m_bColumns) + { + Redraw(); + } + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void SetItemsCount(tUINT64 i_qwItems) + { + m_qwItemsCount = i_qwItems; + + UpdateItemsPerWindow(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void Redraw() + { + if (m_bHelp) + { + return; + } + + tUINT32 l_uiOffset = 1; + + if (m_bColumns) + { + l_uiOffset = 2; + } + + UpdateHeader(); + m_pConsole->SetCursor(m_uX, m_uY + l_uiOffset); + size_t l_szCount = Print() + l_uiOffset; + + if (l_szCount < (size_t)m_uH) + { + m_pConsole->Clear(m_uX, m_uY + (tUINT32)l_szCount, m_uW, m_uH - (tUINT32)l_szCount, m_eWindowBgColor); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual tBOOL Resize(tUINT32 i_uX, tUINT32 i_uY, tUINT32 i_uW, tUINT32 i_uH) + { + m_uX = i_uX; + m_uY = i_uY; + m_uW = i_uW; + m_uH = i_uH; + + UpdateItemsPerWindow(); + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual tBOOL ProcessKey(tUINT16 i_wChar) + { + if (m_bError) + { + return FALSE; + } + + tBOOL l_bReturn = FALSE; + size_t l_szCount = (size_t)m_uH; + tUINT32 l_uiOffset = 1; + + if (m_bColumns) + { + l_uiOffset = 2; + } + + if (m_bHelp) + { + if ((tUINT16)IConsole::eKeyEsc == i_wChar) + { + m_bHelp = FALSE; + l_bReturn = TRUE; + } + + } + else if ( ((tUINT16)IConsole::eKeyF1 == i_wChar) + || ((tUINT16)IConsole::eKeyF2 == i_wChar) + ) + { + m_bHelp = TRUE; + + l_szCount = m_cHelp.Count() - l_uiOffset; + m_pConsole->SetCursor(m_uX, m_uY); + + pAList_Cell l_pEl = NULL; + while (NULL != (l_pEl = m_cHelp.Get_Next(l_pEl))) + { + stHelp *l_pHelp = m_cHelp.Get_Data(l_pEl); + if (l_pHelp) + { + m_pConsole->WriteText(l_pHelp->eFgColor, l_pHelp->eBgColor, m_uW, m_uW, l_pHelp->pString); + } + else + { + l_szCount --; + } + } + } + else if ((tUINT16)IConsole::eKeyArrowLeft == i_wChar) + { + if (m_szOffsetX) + { + m_szOffsetX--; + l_bReturn = TRUE; + m_bUpdateColumns = TRUE; + } + } + else if ((tUINT16)IConsole::eKeyArrowRight == i_wChar) + { + m_szOffsetX++; + m_bUpdateColumns = TRUE; + l_bReturn = TRUE; + } + else if ((tUINT16)IConsole::eKeyArrowUp == i_wChar) + { + if (m_szOffsetY) + { + m_szOffsetY--; + l_bReturn = TRUE; + } + else if (m_qwOffsetWnd) + { + m_qwOffsetWnd--; + l_bReturn = TRUE; + } + } + else if ((tUINT16)IConsole::eKeyArrowDown == i_wChar) + { + if ((m_szOffsetY + 1) < m_szItemsPerWnd) + { + m_szOffsetY++; + l_bReturn = TRUE; + } + else if ((m_qwOffsetWnd + (tUINT64)m_szItemsPerWnd + 1ull) <= m_qwItemsCount) + { + m_qwOffsetWnd++; + l_bReturn = TRUE; + } + } + else if ((tUINT16)IConsole::eKeyPageUp == i_wChar) + { + if (m_qwOffsetWnd > (tUINT64)m_szItemsPerWnd) + { + m_qwOffsetWnd -= (tUINT64)m_szItemsPerWnd; + l_bReturn = TRUE; + } + else if (m_qwOffsetWnd) + { + m_qwOffsetWnd = 0; + m_szOffsetY = 0; + l_bReturn = TRUE; + } + else if (m_szOffsetY) + { + m_szOffsetY = 0; + l_bReturn = TRUE; + } + } + else if ((tUINT16)IConsole::eKeyPageDown == i_wChar) + { + if ((m_qwOffsetWnd + 2ull*(tUINT64)m_szItemsPerWnd) <= m_qwItemsCount) + { + m_qwOffsetWnd += (tUINT64)m_szItemsPerWnd; + l_bReturn = TRUE; + } + else if ((tUINT64)m_szItemsPerWnd <= m_qwItemsCount) + { + m_qwOffsetWnd = m_qwItemsCount - (tUINT64)m_szItemsPerWnd; + m_szOffsetY = m_szItemsPerWnd - 1; + l_bReturn = TRUE; + } + else if (m_qwItemsCount) + { + m_szOffsetY = (size_t)m_qwItemsCount - 1; + l_bReturn = TRUE; + } + } + else if ((tUINT16)IConsole::eKeyHome == i_wChar) + { + m_qwOffsetWnd = 0; + m_szOffsetY = 0; + l_bReturn = TRUE; + } + else if ((tUINT16)IConsole::eKeyEnd == i_wChar) + { + if ((tUINT64)m_szItemsPerWnd <= m_qwItemsCount) + { + m_qwOffsetWnd = m_qwItemsCount - (tUINT64)m_szItemsPerWnd; + m_szOffsetY = m_szItemsPerWnd - 1; + l_bReturn = TRUE; + } + else if (m_qwItemsCount) + { + m_szOffsetY = (size_t)m_qwItemsCount - 1; + l_bReturn = TRUE; + } + } + + if (l_bReturn) + { + UpdateHeader(); + m_pConsole->SetCursor(m_uX, m_uY + l_uiOffset); + l_szCount = Print(); + } + + l_szCount += l_uiOffset; + + if (l_szCount < (size_t)m_uH) + { + m_pConsole->Clear(m_uX, m_uY + (tUINT32)l_szCount, m_uW, m_uH - (tUINT32)l_szCount, m_eWindowBgColor); + } + + return l_bReturn; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual size_t Print() = 0; + +protected: + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void UpdateItemsPerWindow() + { + tUINT32 l_uiH = m_uH - 1; + + if (!m_szLinesPerItem) + { + return; + } + + if ( (m_bColumns) + && (l_uiH) + ) + { + l_uiH --; + } + + m_szItemsPerWnd = l_uiH / m_szLinesPerItem; + if (m_szItemsPerWnd > m_qwItemsCount) + { + m_szItemsPerWnd = (size_t)m_qwItemsCount; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void UpdateHeader() + { + tUINT32 l_uPos = 100; + tUINT64 l_qwOffsY = (tUINT64)m_szOffsetY; + + if ( (l_qwOffsY) + || (1ull == m_qwItemsCount) + ) + { + l_qwOffsY++; + } + + if (m_qwItemsCount) + { + l_uPos = (tUINT32)((100ull * (m_qwOffsetWnd + l_qwOffsY)) / m_qwItemsCount); + } + + m_pConsole->SetCursor(m_uX, m_uY); + m_pConsole->WriteText(IConsole::eBlack, + IConsole::eDarkGray, + m_uW, + m_uW, + TM("{%s} % 3u%% [Help = F1/F2]"), + m_pCaption, + l_uPos + ); + + if (m_bColumns) + { + if (m_bUpdateColumns) + { + pAList_Cell l_pEl = NULL; + size_t l_szLen = 0; + + while ((l_pEl = m_cColumns.Get_Next(l_pEl))) { l_szLen += m_cColumns.Get_Data(l_pEl)->szCaption;} + + if (l_szLen >= m_szColumnsTextMax) + { + if (m_pColumnsText) free(m_pColumnsText); + m_szColumnsTextMax = l_szLen + 16; + m_pColumnsText = (tXCHAR*)malloc(m_szColumnsTextMax * sizeof(tXCHAR)); + } + + + m_szColumnsText = 0; + l_pEl = NULL; + while ((l_pEl = m_cColumns.Get_Next(l_pEl))) + { + stColumn *l_pCol = m_cColumns.Get_Data(l_pEl); + + if ( (l_pCol) + && (l_pCol->bVisible) + ) + { + PStrCpy(m_pColumnsText + m_szColumnsText, m_szColumnsTextMax - m_szColumnsText, l_pCol->pCaption); + m_szColumnsText += l_pCol->szCaption; + } + } + + m_bUpdateColumns = FALSE; + + if (!m_szColumnsText) + { + m_pColumnsText[0] = TM(' '); + m_pColumnsText[1] = 0; + m_szColumnsText = 1; + } + } + + m_pConsole->WriteTextB(m_eItemClFgColor, + m_eItemClBgColor, + m_uW, + m_uW, + m_szOffsetX, + m_pColumnsText, + m_szColumnsText, + m_szColumnsTextMax + ); + + } + } +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CConsoleInput +{ +protected: + tXCHAR *m_pText; + size_t m_szText; + size_t m_szCursor; + tXCHAR *m_pCaption; + tUINT32 m_uX; + tUINT32 m_uY; + tUINT32 m_uW; + tUINT32 m_uH; + + IConsole *m_pConsole; + IConsole::eColor m_eWndFgColor; + IConsole::eColor m_eWndBgColor; + + IConsole::eColor m_eInpFgColor; + IConsole::eColor m_eInpBgColor; + + IConsole::eColor m_eCurFgColor; + IConsole::eColor m_eCurBgColor; + + +public: + struct sCfg + { + tUINT32 uX; + tUINT32 uY; + tUINT32 uW; + tUINT32 uH; + + IConsole *pConsole; + IConsole::eColor eWndFgColor; + IConsole::eColor eWndBgColor; + + IConsole::eColor eInpFgColor; + IConsole::eColor eInpBgColor; + + IConsole::eColor eCurFgColor; + IConsole::eColor eCurBgColor; + + const tXCHAR *pCaption; + + sCfg(tUINT32 i_uX, + tUINT32 i_uY, + tUINT32 i_uW, + tUINT32 i_uH, + IConsole *i_pConsole, + const tXCHAR *i_pCaption + ) + : uX(i_uX) + , uY(i_uY) + , uW(i_uW) + , uH(i_uH) + , pConsole(i_pConsole) + , eWndFgColor(IConsole::eWhite) + , eWndBgColor(IConsole::eDarkGray) + , eInpFgColor(IConsole::eGreen) + , eInpBgColor(IConsole::eLightGray) + , eCurFgColor(IConsole::eWhite) + , eCurBgColor(IConsole::eBlue) + , pCaption(i_pCaption) + { + } + }; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + CConsoleInput(CConsoleInput::sCfg &i_rConfig) + { + UNUSED_ARG(i_rConfig); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~CConsoleInput() + { + + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual void Redraw() + { + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetCaption(const tXCHAR *i_pCaption) + { + if (m_pCaption) + { + PStrFreeDub(m_pCaption); + m_pCaption = NULL; + } + + m_pCaption = i_pCaption ? PStrDub(i_pCaption) : PStrDub(TM("?")); + } + + virtual tBOOL ProcessKey(tUINT16 i_wChar) + { + UNUSED_ARG(i_wChar); + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual tBOOL Apply(const tXCHAR *i_pText) = 0; +}; + +#endif //ICONSOLE_H diff --git a/p7lib/Shared/IFile.h b/p7lib/Shared/IFile.h new file mode 100644 index 0000000..7100e14 --- /dev/null +++ b/p7lib/Shared/IFile.h @@ -0,0 +1,56 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef IFILE_H +#define IFILE_H + + + +//////////////////////////////////////////////////////////////////////////////// +class IFile +{ +public: + enum eFlags + { + EOPEN = 0x00000001UL, + ECREATE = 0x00000002UL, + EACCESS_WRITE = 0x00000004UL, + EACCESS_READ = 0x00000008UL, + ESHARE_WRITE = 0x00000010UL, + ESHARE_READ = 0x00000020UL + }; + +public: + virtual tBOOL IsOpened() = 0; + virtual tBOOL Open(const tXCHAR *i_pName, tUINT32 i_dwFlags) = 0; + virtual tBOOL Close(tBOOL i_bFlush) = 0; + virtual tBOOL Set_Position(tUINT64 i_qwOffset) = 0; + virtual tUINT64 Get_Position() = 0; + virtual tUINT64 Get_Size() = 0; + virtual size_t Write(const tUINT8 *i_pBuffer, + size_t i_szBuffer, + tBOOL i_bFlush + ) = 0; + virtual size_t Read(tUINT8 *o_pBuffer, size_t i_szBuffer) = 0; + + virtual tINT32 Add_Ref() = 0; + virtual tINT32 Release() = 0; +}; + + +#endif //IFILE_H diff --git a/p7lib/Shared/IJournal.h b/p7lib/Shared/IJournal.h new file mode 100644 index 0000000..0fe8e54 --- /dev/null +++ b/p7lib/Shared/IJournal.h @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Simple logger to file/stdout / +// Each start it create new file and delete old files if count of files is more/ +// than allowed / +// It works in different thread / +//////////////////////////////////////////////////////////////////////////////// +#ifndef IJOURNAL_H +#define IJOURNAL_H + +#if !defined(JOURNAL_MODULE) + #define JOURNAL_MODULE NULL +#endif + +#define JADD(i_pLogger, i_eVerb, ...) if (i_pLogger) (i_pLogger)->Log(i_eVerb,\ + JOURNAL_MODULE,\ + __FILE__,\ + __FUNCTION__,\ + __LINE__,\ + __VA_ARGS__); + +#define JOURNAL_TRACE(i_pLogger, ...) JADD(i_pLogger, IJournal::eLEVEL_TRACE, __VA_ARGS__); +#define JOURNAL_DEBUG(i_pLogger, ...) JADD(i_pLogger, IJournal::eLEVEL_DEBUG, __VA_ARGS__); +#define JOURNAL_INFO(i_pLogger, ...) JADD(i_pLogger, IJournal::eLEVEL_INFO, __VA_ARGS__); +#define JOURNAL_WARNING(i_pLogger, ...) JADD(i_pLogger, IJournal::eLEVEL_WARNING, __VA_ARGS__); +#define JOURNAL_ERROR(i_pLogger, ...) JADD(i_pLogger, IJournal::eLEVEL_ERROR, __VA_ARGS__); +#define JOURNAL_CRITICAL(i_pLogger, ...) JADD(i_pLogger, IJournal::eLEVEL_CRITICAL, __VA_ARGS__); + + +//////////////////////////////////////////////////////////////////////////////// +class IJournal +{ +public: + typedef void* hModule; + + enum eTime + { + eTIME_YYYYMMDDHHMMSSMS = 0, + eTIME_YYYYMMDDHHMMSS , + eTIME_HHMMSSMS , + eTIME_HHMMSS + }; + + enum eLevel + { + eLEVEL_TRACE = 0, + eLEVEL_DEBUG , + eLEVEL_INFO , + eLEVEL_WARNING , + eLEVEL_ERROR , + eLEVEL_CRITICAL , + + eLEVEL_COUNT + }; + + virtual tBOOL Initialize(const tXCHAR *i_pName) = 0; + virtual void Set_Verbosity(IJournal::eLevel i_eVerbosity) = 0; + virtual IJournal::eLevel Get_Verbosity() = 0; + + virtual tBOOL Register_Thread(const tXCHAR *i_pName, + tUINT32 i_dwThreadId + ) = 0; + virtual tBOOL Unregister_Thread(tUINT32 i_dwThreadId) = 0; + + virtual tBOOL Register_Module(const tXCHAR *i_pName, + IJournal::hModule *o_hModule + ) = 0; + + virtual tBOOL Log(IJournal::eLevel i_eType, + IJournal::hModule i_hModule, + const char *i_pFile, + const char *i_pFunction, + tUINT32 i_dwLine, + const tXCHAR *i_pFormat, + ... + ) = 0; + + virtual tUINT64 Get_Count(IJournal::eLevel i_eType) = 0; + virtual tINT32 Add_Ref() = 0; + virtual tINT32 Release() = 0; +}; + +#endif //IJOURNAL_H diff --git a/p7lib/Shared/IMEvent.h b/p7lib/Shared/IMEvent.h new file mode 100644 index 0000000..51f70d2 --- /dev/null +++ b/p7lib/Shared/IMEvent.h @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef IMEVENT_H +#define IMEVENT_H + + +//////////////////////////////////////////////////////////////////////////////// +enum eMEvent_Type +{ + EMEVENT_SINGLE_AUTO = 0, + EMEVENT_SINGLE_MANUAL , + EMEVENT_MULTI +}; + + +#define MEVENT_TIME_OUT (0xFFFFFFF) +#define MEVENT_SIGNAL_0 (0) + + +//////////////////////////////////////////////////////////////////////////////// +class IMEvent +{ +public: + //For example + //Init(3, EMEVENT_SINGLE_AUTO, EMEVENT_SINGLE_MANUAL, EMEVENT_MULTI); + virtual tBOOL Init(tUINT8 i_bCount, ...) = 0; + virtual tBOOL Set(tUINT32 i_dwID) = 0; + virtual tBOOL Clr(tUINT32 i_dwID) = 0; + virtual tUINT32 Wait() = 0; + virtual tUINT32 Wait(tUINT32 i_dwMSec) = 0; +}; + +#endif //IMEVENT_H diff --git a/p7lib/Shared/IPerformanceInfo.h b/p7lib/Shared/IPerformanceInfo.h new file mode 100644 index 0000000..ca70129 --- /dev/null +++ b/p7lib/Shared/IPerformanceInfo.h @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef IPERFORMANCE_INFO_H +#define IPERFORMANCE_INFO_H + + +//////////////////////////////////////////////////////////////////////////////// +class IPerformanceInfo +{ +public: + enum eCounter + { + eCounterSystemCpu = 0, + eCounterProcessCpu, + eCounterProcessHandles, + eCounterProcessThreads, + eCounterProcessMemory, + + eCounterTotal + }; + +public: + virtual tBOOL Refresh() = 0; + virtual tINT64 Get(IPerformanceInfo::eCounter i_eCounter) = 0; + virtual tINT32 Add_Ref() = 0; + virtual tINT32 Release() = 0; +}; + + +#endif //IPERFORMANCE_INFO_H diff --git a/p7lib/Shared/ISignal.h b/p7lib/Shared/ISignal.h new file mode 100644 index 0000000..6bca0ee --- /dev/null +++ b/p7lib/Shared/ISignal.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef ISIGNAL_H +#define ISIGNAL_H + +enum eCrashCode +{ + eCrashException, + eCrashPureCall, + eCrashMemAlloc, + eCrashInvalidParameter, + eCrashSignal +}; + +typedef void (__cdecl *fnCrashHandler)(eCrashCode i_eCode, const void *i_pCrashContext, void *i_pUserContext); + +struct stChContext +{ + volatile int iInstalled; + volatile int iProcessed; + void *pUserContext; + fnCrashHandler pUserHandler; +}; + +#endif //ISIGNAL_H \ No newline at end of file diff --git a/p7lib/Shared/Length.h b/p7lib/Shared/Length.h new file mode 100644 index 0000000..8c388a5 --- /dev/null +++ b/p7lib/Shared/Length.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef LENGTH_H +#define LENGTH_H + +template +char (&GetCharArray(Type (&i_pArray)[i_szLength]))[i_szLength]; +#define LENGTH(i_pArray) (sizeof(GetCharArray(i_pArray))) + +#define MEMBER_SIZE(Structure, Memeber) sizeof(((Structure*)0)->Memeber) + +#endif //LENGTH_H diff --git a/p7lib/Shared/Lock.h b/p7lib/Shared/Lock.h new file mode 100644 index 0000000..c08163e --- /dev/null +++ b/p7lib/Shared/Lock.h @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOCK_H +#define LOCK_H + +/////////////////////////////////////////////////////////////////////////////// +#include "PLock.h" + +class CLock +{ + tLOCK m_hCS; + CLock *m_pLock; +public: + CLock() + : m_pLock(NULL) + { + LOCK_CREATE(m_hCS); + } + + CLock(CLock *i_pLock) + : m_pLock(i_pLock) + { + m_pLock->Lock(); + } + + virtual ~CLock() + { + if (NULL == m_pLock) + { + LOCK_DESTROY(m_hCS); + } + else + { + m_pLock->Unlock(); + m_pLock = NULL; + } + } + + inline void Lock() + { + LOCK_ENTER(m_hCS); + } + + inline tBOOL Try() + { + return LOCK_TRY(m_hCS); + } + + inline void Unlock() + { + LOCK_EXIT(m_hCS); + } +}; + +#endif //LOCK_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PAtomic.h b/p7lib/Shared/Platforms/Linux_x86/PAtomic.h new file mode 100644 index 0000000..2843617 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PAtomic.h @@ -0,0 +1,144 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PATOMIC_H +#define PATOMIC_H + +#ifdef __ARM_ARCH_5TEJ__ + + //Source: + //http://svn.dd-wrt.com/browser/src/linux/xscale/linux-2.6.23/arch/arm/kernel/entry-armv.S?rev=8329 + // Reference prototype: + // + // int __kernel_cmpxchg(int oldval, int newval, int *ptr) + // + // Input: + // + // r0 = oldval + // r1 = newval + // r2 = ptr + // lr = return address + // + // Output: + // + // r0 = returned value (zero or non-zero) + // C flag = set if r0 == 0, clear if r0 != 0 + // + // Clobbered: + // + // r3, ip, flags + // + // Definition and user space usage example: + // + // typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); + // #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) + // + // Atomically store newval in *ptr if *ptr is equal to oldval for user space. + // Return zero if *ptr was changed or non-zero if no exchange happened. + // The C flag is also set if *ptr was changed to allow for assembly + // optimization in the calling code. + // + // Notes: + // + // - This routine already includes memory barriers as needed. + // + // - A failure might be transient, i.e. it is possible, although unlikely, + // that "failure" be returned even if *ptr == oldval. + // + //Another implementations: + //http://upc.lbl.gov/web-translator/2.8.0/runtime/inst/opt/include/gasnet_atomic_bits.h + //http://upc.lbl.gov/web-translator/ - in last versions very interesting + // For arm 6 & 7: + //http://lxr.free-electrons.com/source/arch/arm/include/asm/atomic.h + + #define ATOMIC_ADD(ptr, val) \ + __extension__ ({ volatile register tINT32 *__ptr asm("r2") = (ptr); \ + register tINT32 __result asm("r1"); \ + asm volatile ( \ + "1: @ atomic_add\n\t" \ + "ldr r0, [r2]\n\t" \ + "mov r3, #0xffff0fff\n\t" \ + "add lr, pc, #4\n\t" \ + "add r1, r0, %2\n\t" \ + "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + "bcc 1b" \ + : "=&r" (__result) \ + : "r" (__ptr), "rIL" (val) \ + : "r0","r3","ip","lr","cc","memory" ); \ + __result; }) + + + #define ATOMIC_SUB(ptr, val) \ + __extension__ ({ volatile register tINT32 *__ptr asm("r2") = (ptr); \ + register tINT32 __result asm("r1"); \ + asm volatile ( \ + "1: @ atomic_add\n\t" \ + "ldr r0, [r2]\n\t" \ + "mov r3, #0xffff0fff\n\t" \ + "add lr, pc, #4\n\t" \ + "sub r1, r0, %2\n\t" \ + "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ + "bcc 1b" \ + : "=&r" (__result) \ + : "r" (__ptr), "rIL" (val) \ + : "r0","r3","ip","lr","cc","memory" ); \ + __result; }) + +//#ifdef __ARM_ARCH_5TEJ__ +#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_6__) + #define ATOMIC_ADD(ptr, val) \ + __extension__ ({ int32_t tmp; \ + int result; \ + __asm__ __volatile__("@ atomic_add\n" \ + "1: ldrex %0, [%3]\n" \ + " add %0, %0, %4\n" \ + " strex %1, %0, [%3]\n" \ + " teq %1, #0\n" \ + " bne 1b" \ + : "=&r" (result), "=&r" (tmp), "+Qo" (*ptr) \ + : "r" (ptr), "Ir" (val) \ + : "cc"); \ + result;}) + + #define ATOMIC_SUB(ptr, val) \ + __extension__ ({ unsigned long tmp; \ + int result; \ + __asm__ __volatile__("@ atomic_sub\n" \ + "1: ldrex %0, [%3]\n" \ + " sub %0, %0, %4\n" \ + " strex %1, %0, [%3]\n" \ + " teq %1, #0\n" \ + " bne 1b" \ + : "=&r" (result), "=&r" (tmp), "+Qo" (*ptr) \ + : "r" (ptr), "Ir" (val) \ + : "cc"); \ + result;}) +#else //#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_6__) + + #define ATOMIC_ADD(io_Val, i_Add) __sync_add_and_fetch(io_Val, i_Add) + #define ATOMIC_SUB(io_Val, i_Add) __sync_sub_and_fetch(io_Val, i_Add) + #define ATOMIC_SET(io_Var, i_Val) __sync_lock_test_and_set(io_Var, i_Val) + +#endif //#ifdef __ARM_ARCH_5TEJ__ + + +#define ATOMIC_INC(io_Val) ATOMIC_ADD(io_Val, 1) +#define ATOMIC_DEC(io_Val) ATOMIC_SUB(io_Val, 1) + +#endif //PATOMIC_H + diff --git a/p7lib/Shared/Platforms/Linux_x86/PCRC32.h b/p7lib/Shared/Platforms/Linux_x86/PCRC32.h new file mode 100644 index 0000000..307d114 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PCRC32.h @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PCRC32_H +#define PCRC32_H + + +//////////////////////////////////////////////////////////////////////////////// +//Get_CRC32 +//This function implement 2 calculation kinds: +// * AT&T assembler for X86 architecture for GNU C compiler +// * standard C function for all other cases like X64 or ARM +//Assembler code if faster than generated by GCC (o2) up to 1% it is not a lot +//but for big amount of data and often calculation is enough to use it. +static UNUSED_FUNC tUINT32 Get_CRC32(tUINT8 *i_pData, size_t i_szCount) +{ + tUINT32 l_dwResult = 0xFFFFFFFF; + + if ( (NULL == i_pData) + || (0 >= i_szCount) + ) + { + return l_dwResult; + } + +#if defined(__i386__) && defined(__GNUC__) && !defined(__PIC__) + // Register use: + // eax - CRC32 value + // ebx - a lot of things + // ecx - CRC32 value + // edx - address of end of buffer + // esi - address of start of buffer + // edi - CRC32 table + + __asm__("push %%esi;" // Save the esi and edi registers + "push %%edi;" + //"movl l_dwResult, %%ecx;" do it already by constraints + //"movl g_ppCRC32_Table, %%edi;" + "leal (%%esi,%%ebx),%%edx;" // Calculate the end of the buffer + "crc32loop:;" + "xorl %%eax, %%eax;" // Clear the eax register" + "movb (%%esi), %%bl;" + "movb %%cl, %%al;" // Copy crc value into eax + "incl %%esi;" // Advance the source pointer + "xorb %%bl, %%al;" // Create the index into the CRC32 table + "shr $8, %%ecx;" + "movl (%%edi, %%eax, 4), %%ebx;" // Get the value out of the table + "xorl %%ebx, %%ecx;" // xor with the current byte + "cmpl %%edx, %%esi;" // Have we reached the end of the buffer? + "jne crc32loop;" + "pop %%edi;" + "pop %%esi;" + + //output + :"=c"(l_dwResult) + //input + :"D"(g_ppCRC32_Table), "c"(l_dwResult), "S"(i_pData), "b"(i_szCount) + ); +#else + for (size_t l_szI = 0; l_szI < i_szCount; l_szI ++) + { + l_dwResult = g_ppCRC32_Table[(l_dwResult ^ i_pData[l_szI]) & 0xFF ] ^ (l_dwResult >> 8); + } + /* Suppress warning that this is not used */ + (void)g_ppCRC32_Table; +#endif + return l_dwResult; +} + +#endif //PCRC32_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PConsole.h b/p7lib/Shared/Platforms/Linux_x86/PConsole.h new file mode 100644 index 0000000..289507a --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PConsole.h @@ -0,0 +1,712 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PCONSOLE_H +#define PCONSOLE_H + +#include +#include +#include +#include +#include +#include "IConsole.h" +#include "RBTree.h" +#include "AList.h" + +//////////////////////////////////////////////////////////////////////////////// +//Is_Key_Hit +static __attribute__ ((unused)) tBOOL Is_Key_Hit(void) +{ + struct termios oldt, newt; + int ch; + int oldf; + + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + oldf = fcntl(STDIN_FILENO, F_GETFL, 0); + fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); + + ch = getchar(); + + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + fcntl(STDIN_FILENO, F_SETFL, oldf); + + if(ch != EOF) + { + ungetc(ch, stdin); + return TRUE; + } + + return FALSE; +}//Is_Key_Hit + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Char +static __attribute__ ((unused)) tXCHAR Get_Char() +{ + return getchar(); +}//Get_Char + + +//////////////////////////////////////////////////////////////////////////////// +//SetEchoOff +static __attribute__ ((unused)) void Set_EchoOff(tBOOL i_bOff) +{ + struct termios termInfo; + + if (-1 == tcgetattr(0,&termInfo)) + { + return; + } + + if (i_bOff) + { + termInfo.c_lflag &= ~ECHO; //turn off ECHO + } + else + { + termInfo.c_lflag |= ECHO; //turn on ECHO + } + tcsetattr(0, 0, &termInfo); +}//Get_Char + + +//////////////////////////////////////////////////////////////////////////////// +struct stKeyMap +{ + tUINT16 wKey; + tUINT64 qwHash; + stKeyMap(tUINT16 i_wKey, + tUINT8 i_pv7, + tUINT8 i_pv6, + tUINT8 i_pv5, + tUINT8 i_pv4, + tUINT8 i_pv3, + tUINT8 i_pv2, + tUINT8 i_pv1, + tUINT8 i_pv0 + ) + : wKey(i_wKey), qwHash(0) + { + qwHash = ((tUINT64)i_pv7 << 56) + | ((tUINT64)i_pv6 << 48) + | ((tUINT64)i_pv5 << 40) + | ((tUINT64)i_pv4 << 32) + | ((tUINT64)i_pv3 << 24) + | ((tUINT64)i_pv2 << 16) + | ((tUINT64)i_pv1 << 8) + | (tUINT64)i_pv0; + } + + stKeyMap(tUINT16 i_wKey, + tUINT8 i_pv4, + tUINT8 i_pv3, + tUINT8 i_pv2, + tUINT8 i_pv1, + tUINT8 i_pv0 + ) + : wKey(i_wKey), qwHash(0) + { + qwHash = ((tUINT64)i_pv4 << 32) + | ((tUINT64)i_pv3 << 24) + | ((tUINT64)i_pv2 << 16) + | ((tUINT64)i_pv1 << 8) + | (tUINT64)i_pv0; + } + + stKeyMap(tUINT16 i_wKey, + tUINT8 i_pv3, + tUINT8 i_pv2, + tUINT8 i_pv1, + tUINT8 i_pv0 + ) + : wKey(i_wKey), qwHash(0) + { + qwHash = ((tUINT64)i_pv3 << 24) + | ((tUINT64)i_pv2 << 16) + | ((tUINT64)i_pv1 << 8) + | (tUINT64)i_pv0; + } + + stKeyMap(tUINT16 i_wKey, + tUINT8 i_pv2, + tUINT8 i_pv1, + tUINT8 i_pv0 + ) + : wKey(i_wKey), qwHash(0) + { + qwHash = ((tUINT64)i_pv2 << 16) + | ((tUINT64)i_pv1 << 8) + | (tUINT64)i_pv0; + } + + stKeyMap(tUINT16 i_wKey, + tUINT8 i_pv1, + tUINT8 i_pv0 + ) + : wKey(i_wKey), qwHash(0) + { + qwHash = ((tUINT64)i_pv1 << 8) + | (tUINT64)i_pv0; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +//CKeysTree +class CKeysList + : public CListPool +{ +protected: + virtual tBOOL Data_Release(char i_pData) + { + UNUSED_ARG(i_pData); + return TRUE; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +//CKeysTree +class CKeysTree: + public CRBTree +{ +public: + //////////////////////////////////////////////////////////////////////////// + //~CKeysTree + virtual ~CKeysTree() + { + Clear(); + }//~CRBTree + +protected: + //////////////////////////////////////////////////////////////////////////// + virtual tBOOL Data_Release(stKeyMap* i_pData) + { + delete i_pData; + return TRUE; //memory used from pool, not necessary to return + }// Data_Release + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(tUINT64 i_pKey, stKeyMap *i_pData) + { + return (i_pKey < i_pData->qwHash); + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(tUINT64 i_pKey, stKeyMap *i_pData) + { + return (i_pKey == i_pData->qwHash); + } +};//CDesc_Tree + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CConsole + : public IConsole +{ + tUINT32 m_pCl[IConsole::eColorsMax]; + size_t m_szText; + tXCHAR *m_pText; + tXCHAR *m_pEmpty; + size_t m_szEmpty; + CKeysTree m_pKeys; + CKeysList m_cKeysList; +public: + CConsole() + { + m_szText = 32768; + m_pText = (tXCHAR*)malloc(m_szText * sizeof(tXCHAR)); + + m_szEmpty = 0; + m_pEmpty = NULL; + AllocEmptyString(1024); + + Set_EchoOff(TRUE); + + //https://en.wikipedia.org/wiki/ANSI_escape_code + m_pCl[IConsole::eBlack] = 0; + m_pCl[IConsole::eBlue] = 12; + m_pCl[IConsole::eGreen] = 40; + m_pCl[IConsole::eCyan] = 51; + m_pCl[IConsole::eRed] = 124; + m_pCl[IConsole::eMagenta] = 129; + m_pCl[IConsole::eBrown] = 94; + m_pCl[IConsole::eLightGray] = 252; + m_pCl[IConsole::eDarkGray] = 244; + m_pCl[IConsole::eLightBlue] = 33; + m_pCl[IConsole::eLightGreen] = 48; + m_pCl[IConsole::eLightCyan] = 195; + m_pCl[IConsole::eLightRed] = 196; + m_pCl[IConsole::eLightMagenta] = 201; + m_pCl[IConsole::eYellow] = 11; + m_pCl[IConsole::eWhite] = 15; + + stKeyMap *l_pKey = new stKeyMap(eKeyArrowLeft, 27,91,68); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyArrowRight, 27,91,67); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyArrowDown, 27,91,66); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyArrowUp, 27,91,65); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyPageUp, 27,91,53,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyPageDown, 27,91,54,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyHome, 27,79,72); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyEnd, 27,79,70); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyDel, 27,91,51,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyInsert, 27,91,50,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF1, 27,79,80); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF2, 27,79,81); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF3, 27,79,82); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF4, 27,79,83); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF5, 27,91,49,53,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF6, 27,91,49,55,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF7, 27,91,49,56,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF8, 27,91,49,57,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF9, 27,91,50,48,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF10, 27,91,50,49,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF11, 27,91,50,51,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + + l_pKey = new stKeyMap(eKeyF12, 27,91,50,52,126); + m_pKeys.Push(l_pKey, l_pKey->qwHash); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~CConsole() + { + if (m_pText) + { + free(m_pText); + m_pText = NULL; + } + + if (m_pEmpty) + { + free(m_pEmpty); + m_pEmpty = NULL; + } + + m_pKeys.Clear(); + m_cKeysList.Clear(TRUE); + Set_EchoOff(FALSE); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL SetCursor(tUINT32 i_uX, tUINT32 i_uY) + { + printf("\033[%d;%dH", i_uY+1, i_uX+1); + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetCursorX() + { + return 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL GetInput(IConsole::sInput &o_rInput) + { + while (Is_Key_Hit()) + { + m_cKeysList.Add_After(m_cKeysList.Get_Last(), Get_Char()); + } + + if (!m_cKeysList.Count()) + { + return FALSE; + } + + char l_cVal = m_cKeysList.Get_Data(m_cKeysList.Get_First()); + tBOOL l_bReturn = FALSE; + + o_rInput.eEvent = IConsole::eKey; + o_rInput.stKey.bDown = TRUE; + o_rInput.stKey.uControls = 0; + o_rInput.stKey.wCount = 1; + o_rInput.stKey.wKey = l_cVal; + + if ( (27 == l_cVal) //escape sequence + && (m_cKeysList.Count()) + ) + { + tUINT64 l_qwHash = 0; + pAList_Cell l_pEl = m_cKeysList.Get_First(); + stKeyMap *l_pKey = NULL; + tUINT32 l_uiCount = 0; + + while ( (l_pEl) + && (8 > l_uiCount) + ) + { + l_uiCount++; + + l_qwHash = (l_qwHash << 8) | m_cKeysList.Get_Data(l_pEl); + l_pKey = m_pKeys.Find(l_qwHash); + if (l_pKey) + { + o_rInput.stKey.wKey = l_pKey->wKey; + l_bReturn = TRUE; + + while (l_pEl) //clear esc sequence used to identefy key + { + pAList_Cell l_pPrevEl = m_cKeysList.Get_Prev(l_pEl); + m_cKeysList.Del(l_pEl, TRUE); + l_pEl = l_pPrevEl; + } + + break; + } + else + { + l_pEl = m_cKeysList.Get_Next(l_pEl); + } + } + } + + if (!l_bReturn) //if it is not esc sequence - get first char and return it + { + if (10 == l_cVal) + { + o_rInput.stKey.wKey = (tUINT16)IConsole::eKeyEnter; + } + else if (9 == l_cVal) + { + o_rInput.stKey.wKey = (tUINT16)IConsole::eKeyTab; + } + else if (8 == l_cVal) + { + o_rInput.stKey.wKey = (tUINT16)IConsole::eKeyBackSpace; + } + + l_bReturn = TRUE; + m_cKeysList.Del(m_cKeysList.Get_First(), TRUE); + } + + return l_bReturn; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetCursorY() + { + return 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetWidth() + { + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + return w.ws_col; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetHeight() + { + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + return w.ws_row; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL SetTextAttr(IConsole::eColor i_eFg, IConsole::eColor i_eBg) + { + if ( (i_eFg < 0) + || (i_eFg >= IConsole::eColorsMax) + || (i_eBg < 0) + || (i_eBg >= IConsole::eColorsMax) + ) + { + return FALSE; + } + + printf("\x1b[38;5;%dm\x1b[48;5;%dm", m_pCl[i_eFg], m_pCl[i_eBg]); + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Clear() + { + printf("\033[H\033[J"); + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Clear(tUINT32 i_uX, tUINT32 i_uY, tUINT32 i_uW, tUINT32 i_uH, IConsole::eColor i_eBg) + { + tUINT32 l_uiW = GetWidth(); + tUINT32 l_uiH = GetHeight(); + + if ( (i_uX > l_uiW) + || (i_uY > l_uiH) + || (!i_uW) + || (!i_uH) + || (i_uW >= m_szEmpty) + ) + { + return FALSE; + } + + if ((i_uX + i_uW) > l_uiW) + { + i_uW = l_uiW - i_uX; + } + + if ((i_uY + i_uH) > l_uiH) + { + i_uH = l_uiH - i_uY; + } + + if (i_uW > m_szEmpty) + { + if (!AllocEmptyString((size_t)i_uW)) + { + return FALSE; + } + } + + if (!SetTextAttr(IConsole::eBlack, i_eBg)) + { + return FALSE; + } + + SetCursor(i_uX, i_uY); + + tUINT32 l_uiXOld = i_uX; + tUINT32 l_uiYOld = i_uY; + while (i_uH--) + { + SetCursor(i_uX, i_uY++); + m_pEmpty[i_uW] = 0; + WriteTextB(m_pEmpty, i_uW); + m_pEmpty[i_uW] = ' '; + } + + SetCursor(l_uiXOld, l_uiYOld); + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t WriteTextB(const tXCHAR *i_pText, size_t i_szText) + { + UNUSED_ARG(i_szText); + return (size_t)printf("%s", i_pText); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t WriteTextB(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + tXCHAR *i_pText, + size_t i_szText, + size_t i_szTextMax + ) + { + if ( (i_szLenMin > i_szLenMax) + || (!i_pText) + || (8 >= i_szTextMax) + || (i_szText >= i_szTextMax) + ) + { + return 0; + } + + if (!SetTextAttr(i_eFg, i_eBg)) + { + return 0; + } + + tXCHAR *l_pText = i_pText; + + if (!i_szText) + { + i_szText = PStrLen(i_pText); + } + + //if there is offset, recalculate all inputs + if (i_szOffset) + { + if (i_szOffset < i_szText) //set sext offset and recalculate all + { + l_pText = l_pText + i_szOffset; + i_szText -= i_szOffset; + i_szTextMax -= i_szOffset; + i_szOffset = 0; + *l_pText = TM('<'); + } + else //if (i_szOffset >= i_szText) + { + l_pText = m_pText; + *l_pText = TM('<'); + i_szText = 1; + i_szTextMax= m_szText; + } + } + + + if (i_szText > i_szLenMax) + { + i_szText = i_szLenMax; + l_pText[i_szText-1] = TM('>'); + } + else if (i_szText < i_szLenMin) + { + if (i_szTextMax < (i_szLenMin + 1)) + { + PStrNCpy(m_pText, m_szText, l_pText, i_szText); + l_pText = m_pText; + i_szTextMax = m_szText; + } + + tXCHAR *l_pIter = l_pText + i_szText; + + while (i_szText < i_szLenMin) + { + *l_pIter = TM(' '); + l_pIter ++; + i_szText++; + } + } + + if (i_szText < i_szTextMax) + { + l_pText[i_szText] = 0; + } + else + { + l_pText[i_szText-1] = 0; + } + + return (size_t)printf("%s", l_pText); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t WriteTextF(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + const tXCHAR *i_pFormat, + va_list i_pVA + ) + { + int l_iReturn = PVsnprintf(m_pText, m_szText, i_pFormat, i_pVA); + + if (0 > l_iReturn) + { + return 0; + } + + return WriteTextB(i_eFg, i_eBg, i_szLenMin, i_szLenMax, i_szOffset, m_pText, (size_t)l_iReturn, m_szText); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Present() + { + return TRUE; + } + +protected: + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL AllocEmptyString(size_t i_szEmpty) + { + if (m_pEmpty) + { + free(m_pEmpty); + } + + if (i_szEmpty > 4096) + { + i_szEmpty = 4096; + } + + m_szEmpty = i_szEmpty; + m_pEmpty = (tXCHAR*)malloc(m_szEmpty * sizeof(tXCHAR)); + + if (!m_pEmpty) + { + return FALSE; + } + + tXCHAR *l_pEmpty = m_pEmpty; + size_t l_szIterator = m_szEmpty; + + while (l_szIterator--) + { + *l_pEmpty = TM(' '); + l_pEmpty++; + } + + return TRUE; + } +}; + + + +#endif //PCONSOLE_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PCrashDump.h b/p7lib/Shared/Platforms/Linux_x86/PCrashDump.h new file mode 100644 index 0000000..6eb6ab6 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PCrashDump.h @@ -0,0 +1,229 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus + +#ifndef PCRASH_DUMP_H +#define PCRASH_DUMP_H + +#include "GTypes.h" +#include "Length.h" +#include "PString.h" +#include "WString.h" +#include "AList.h" +#include "PAtomic.h" +#include "ISignal.h" + +#define CH_DESC_FILE_EXT TM("dsc") + +struct sCdContext +{ + char *pBuffer; + size_t szBuffer; + size_t szPathMax; + char *pDescFileName; +}; + + +//////////////////////////////////////////////////////////////////////////////// +//CdCreateDumpTxt +static __attribute__ ((unused)) void CdCreateDumpTxt(sCdContext *i_pCdContext, const char *i_pText, tUINT64 i_qwCode) +{ + UNUSED_ARG(i_pCdContext); + UNUSED_ARG(i_pText); + UNUSED_ARG(i_qwCode); +}//CdCreateDumpTxt + + +//////////////////////////////////////////////////////////////////////////////// +//CdWrite +static __attribute__ ((unused)) void CdWrite(void *i_pCdInfo, eCrashCode i_eCode, const void *i_pContext) +{ + UNUSED_ARG(i_pCdInfo); + UNUSED_ARG(i_eCode); + UNUSED_ARG(i_pContext); + + //sCdContext *l_pCrush = (sCdContext*)i_pCdInfo; + // + //if ( IBreakdownNotify::eException == i_eCode ) + //{ + // if (i_pContext) + // { + // _EXCEPTION_POINTERS l_sException = *(_EXCEPTION_POINTERS*)(i_pContext); + // + // char l_pText[128]; + // sprintf_s(l_pText, + // _countof(l_pText), + // "Exception 0x%08X", + // l_sException.ExceptionRecord->ExceptionCode + // ); + // + // tUINT64 l_qwCode = CdCreateDumpBin(&l_sException); + // CdCreateDumpTxt(l_pCrush, l_pText, l_qwCode); + // + // } + //} + //else if (IBreakdownNotify::ePureCall == i_eCode) + //{ + // CdCreateDumpTxt(l_pCrush, (const char*)i_pContext, i_eCode); + //} + //else if (IBreakdownNotify::eMemAlloc == i_eCode) + //{ + // CdCreateDumpTxt(l_pCrush, (const char*)i_pContext, i_eCode); + //} + //else if (IBreakdownNotify::eInvalidParameter == i_eCode) + //{ + // CdCreateDumpTxt(l_pCrush, (const char*)i_pContext, i_eCode); + //} + //else if ( IBreakdownNotify::eSignal >= i_eCode) + //{ + // CdCreateDumpTxt(l_pCrush, (const char*)i_pContext, i_eCode); + //} +}//CdWrite + + +//////////////////////////////////////////////////////////////////////////////// +//CdCleanUp +static __attribute__ ((unused)) void CdCleanUp(const tXCHAR *i_pDir, unsigned int i_dwMax_Count) +{ + CBList l_cFiles; + CWString l_cDir; + + l_cDir.Set(i_pDir); + CFSYS::Enumerate_Files(&l_cFiles, &l_cDir, TM("*.") CH_DESC_FILE_EXT, 0); + + //sort files - first is oldest, last is newest ! + pAList_Cell l_pStart = NULL; + tUINT32 l_dwDirLen = l_cDir.Length(); + + while ((l_pStart = l_cFiles.Get_Next(l_pStart))) + { + pAList_Cell l_pMin = l_pStart; + pAList_Cell l_pIter = l_pStart; + + while ((l_pIter = l_cFiles.Get_Next(l_pIter))) + { + CWString *l_pPathM = l_cFiles.Get_Data(l_pMin); + CWString *l_pPathI = l_cFiles.Get_Data(l_pIter); + tXCHAR *l_pNameM = l_pPathM->Get() + l_dwDirLen; + tXCHAR *l_pNameI = l_pPathI->Get() + l_dwDirLen; + + if (0 < PStrICmp(l_pNameM, l_pNameI)) + { + l_pMin = l_pIter; + } + } + + if (l_pMin != l_pStart) + { + l_cFiles.Extract(l_pMin); + l_cFiles.Put_After(l_cFiles.Get_Prev(l_pStart), l_pMin); + l_pStart = l_pMin; + } + } //while (l_pStart = m_cFiles.Get_Next(l_pStart)) + + //delete oldest files + while (l_cFiles.Count() > i_dwMax_Count) + { + l_pStart = l_cFiles.Get_First(); + if (l_pStart) + { + CWString *l_pPath = l_cFiles.Get_Data(l_pStart); + + //delete description file + CFSYS::Delete_File(l_pPath->Get()); + + l_cFiles.Del(l_pStart, TRUE); + } + }//while (l_cFiles.Count() > i_dwMax_Count) +}//CdCleanUp + + +//////////////////////////////////////////////////////////////////////////////// +//CdAlloc +static __attribute__ ((unused)) void *CdAlloc(const tXCHAR *i_pFolder) +{ + sCdContext *l_pCrush = (sCdContext*)malloc(sizeof(sCdContext)); + tBOOL l_bError = FALSE; + + if ( !l_pCrush ) + { + return NULL; + } + + + //////////////////////////////////////////////////////////////////////////// + //initialize parameters + memset(l_pCrush, 0, sizeof(sCdContext)); + + l_pCrush->szBuffer = 32768; + l_pCrush->pBuffer = (char*)malloc(l_pCrush->szBuffer * sizeof(char)); + l_pCrush->szPathMax = 16384; + l_pCrush->pDescFileName = (tXCHAR*)malloc(l_pCrush->szPathMax * sizeof(tXCHAR)); + + if ( (NULL == l_pCrush->pBuffer) + || (NULL == l_pCrush->pDescFileName) + ) + { + l_bError = TRUE; + goto l_lblExit; + } + + CdCleanUp(i_pFolder, 5); + + +l_lblExit: + if ( (l_bError) + && (l_pCrush) + ) + { + free(l_pCrush); + l_pCrush = NULL; + } + + + return l_pCrush; +}//CH_Install + + + +//////////////////////////////////////////////////////////////////////////////// +//CdFree +static __attribute__ ((unused)) void CdFree(void *i_pCdInfo) +{ + sCdContext *l_pCrush = (sCdContext*)i_pCdInfo; + + if ( !l_pCrush ) + { + return; + } + + if (l_pCrush->pBuffer) + { + free(l_pCrush->pBuffer); + l_pCrush->pBuffer = NULL; + } + + if (l_pCrush->pDescFileName) + { + free(l_pCrush->pDescFileName); + l_pCrush->pDescFileName = NULL; + } +}//CdFree + +#endif //PCRASH_DUMP_H \ No newline at end of file diff --git a/p7lib/Shared/Platforms/Linux_x86/PDnsTxtResolver.h b/p7lib/Shared/Platforms/Linux_x86/PDnsTxtResolver.h new file mode 100644 index 0000000..18b7a71 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PDnsTxtResolver.h @@ -0,0 +1,89 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#include +//#include +#include +#include + +#include "GTypes.h" +#include "AList.h" + +class CDnsTxt: public CAList +{ +protected: + virtual tBOOL Data_Release(tACHAR *i_pStr) + { + if (NULL == i_pStr) + { + return FALSE; + } + + free(i_pStr); + return TRUE; + }//CListBase::Data_Release +}; + + +tBOOL static inline GetDnsTxtRecords(const tACHAR *i_pDomain, CDnsTxt &io_rList) +{ + const size_t l_szTxtBuf = 2048; + u_char l_pTxtBuf[l_szTxtBuf]; + int l_iResult = -1; + int l_iLen = 0; + ns_msg l_stMsg = {0}; + ns_rr l_stRr = {0}; + tUINT16 l_sMsgCount= 0; + + l_iLen = res_query(i_pDomain, ns_c_in, ns_t_txt, l_pTxtBuf, (int)l_szTxtBuf); + if (l_iLen < 0) + { + return FALSE; + } + + l_iResult = ns_initparse(l_pTxtBuf, l_iLen, &l_stMsg); + if (l_iResult < 0) + { + return FALSE; + } + + l_sMsgCount = ns_msg_count(l_stMsg, ns_s_an); + for (tUINT16 i = 0; i < l_sMsgCount; i++) + { + if ( (0 == ns_parserr(&l_stMsg, ns_s_an, i, &l_stRr)) + && (l_stRr.rdlength) + ) + { + tACHAR *l_pText = (tACHAR*)malloc(l_stRr.rdlength-1); + if (l_pText) + { + //TXT record RDATA format is: + // length, 1 byte + // string, + // length2, 1 byte + // string2, + // etc. + memcpy(l_pText, (tACHAR *)l_stRr.rdata + 1, l_stRr.rdlength - 1); + l_pText[l_stRr.rdlength - 1] = 0; + io_rList.Push_Last(l_pText); + } + } + } + + return (io_rList.Count() != 0); +} diff --git a/p7lib/Shared/Platforms/Linux_x86/PFile.h b/p7lib/Shared/Platforms/Linux_x86/PFile.h new file mode 100644 index 0000000..24279ee --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PFile.h @@ -0,0 +1,291 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PFILE_H +#define PFILE_H + +#define PFILE_INVALID_HANDLE (-1) + +#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE +#endif +//Headers have to be included in application source files +#include +#include +#include +#include +#include + +#define GetLastError() errno + +//UTF-8 text file header - {0xEF, 0xBB, 0xBF} + +//////////////////////////////////////////////////////////////////////////////// +class CPFile + : public IFile //virtual +{ + volatile tINT32 m_iRCnt; + //tLOCK m_hCS; + int m_iFile; +public: + //////////////////////////////////////////////////////////////////////////// + CPFile() + : m_iRCnt(1) + , m_iFile(-1) + { + //LOCK_CREATE(m_hCS); + } + + //////////////////////////////////////////////////////////////////////////// + virtual ~CPFile() + { + //LOCK_DESTROY(m_hCS); + Close(FALSE); + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL IsOpened() + { + return (PFILE_INVALID_HANDLE != m_iFile); + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Open(const tXCHAR *i_pName, tUINT32 i_dwFlags) + { + //create file if it is not exists, else - open, heh ... engineers + //friendly POSIX API :-( + int l_iFlags = O_CREAT; + mode_t l_tMode = 0; + + if (PFILE_INVALID_HANDLE != m_iFile) + { + Close(TRUE); + } + + l_iFlags |= O_RDWR; + + if (ECREATE & i_dwFlags) + { + l_iFlags |= O_TRUNC; + + if (EACCESS_WRITE & i_dwFlags) + { + l_tMode = S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH; + } + else if (EACCESS_READ & i_dwFlags) + { + l_tMode = S_IRUSR | S_IRGRP | S_IROTH; + } + } + + m_iFile = open(i_pName, l_iFlags, l_tMode); + + return (PFILE_INVALID_HANDLE != m_iFile) ? TRUE : FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Close(tBOOL i_bFlush) + { + tBOOL l_bReturn = TRUE; + int l_iTemp = PFILE_INVALID_HANDLE; + + if (PFILE_INVALID_HANDLE == m_iFile) + { + return TRUE; + } + + if (i_bFlush) + { + if (-1 == fsync(m_iFile)) + { + l_bReturn = FALSE; + goto l_lExit; + } + } + + l_iTemp = m_iFile; + m_iFile = PFILE_INVALID_HANDLE; + + if (-1 == close(l_iTemp)) + { + l_bReturn = FALSE; + goto l_lExit; + } + + l_lExit: + return l_bReturn; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Set_Position(tUINT64 i_qwOffset) + { + if (PFILE_INVALID_HANDLE == m_iFile) + { + return FALSE; + } + + + if ((off64_t)i_qwOffset != lseek64(m_iFile, (off64_t)i_qwOffset, SEEK_SET)) + { + return FALSE; + } + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////// + tUINT64 Get_Position() + { + if (PFILE_INVALID_HANDLE == m_iFile) + { + return 0ULL; + } + + return (off64_t)lseek64(m_iFile, 0LL, SEEK_CUR); + } + + //////////////////////////////////////////////////////////////////////////// + tUINT64 Get_Size() + { + if (PFILE_INVALID_HANDLE == m_iFile) + { + return 0ULL; + } + + off64_t l_llPos = lseek64(m_iFile, 0LL, SEEK_CUR); + off64_t l_llSize = lseek64(m_iFile, 0LL, SEEK_END); + lseek64(m_iFile, l_llPos, SEEK_SET); + return l_llSize; + } + + //////////////////////////////////////////////////////////////////////////// + size_t Write(const tUINT8 *i_pBuffer, size_t i_szBuffer, tBOOL i_bFlush) + { + if ( (PFILE_INVALID_HANDLE == m_iFile) + || (NULL == i_pBuffer) + || (0 == i_szBuffer) + ) + { + return 0ULL; + } + + ssize_t l_szRes = 0; + size_t l_szWritten = 0; + int l_iError = 0; + + while (l_szWritten < i_szBuffer) + { + l_szRes = write(m_iFile, i_pBuffer + l_szWritten, i_szBuffer - l_szWritten); + if (0 < l_szRes) + { + l_szWritten += (size_t)l_szRes; + } + else + { + l_iError = errno; + printf("%d", l_iError); + break; + } + } + + if ( (i_bFlush) + && (l_szWritten) + ) + { + fsync(m_iFile); + } + + return l_szWritten; + } + + //////////////////////////////////////////////////////////////////////////// + size_t Read(tUINT8 *o_pBuffer, size_t i_szBuffer) + { + if ( (PFILE_INVALID_HANDLE == m_iFile) + || (NULL == o_pBuffer) + || (0 == i_szBuffer) + ) + { + return 0ULL; + } + + size_t l_szRead = 0; + ssize_t l_szRes = 0; + + while (l_szRead < i_szBuffer) + { + l_szRes = read(m_iFile, o_pBuffer + l_szRead, i_szBuffer - l_szRead); + if (0 < l_szRes) + { + l_szRead += (size_t)l_szRes; + } + else + { + break; + } + } + + return l_szRead; + } + + + //////////////////////////////////////////////////////////////////////////// + tINT32 Add_Ref() + { + return ATOMIC_INC(&m_iRCnt); + } + + + //////////////////////////////////////////////////////////////////////////// + tINT32 Release() + { + volatile tINT32 l_iReturn = ATOMIC_DEC(&m_iRCnt); + + if (0 >= l_iReturn) + { + delete this; + } + + return l_iReturn; + } +}; + +#endif //PFILE_H + + + +/* + CPFile l_cFile; + const tUINT8 l_pHeader[] = {0xEF, 0xBB, 0xBF}; + const char l_pText[] = "Some Text For me !\xD\xA Another Text\xD\xA Third Text"; + tUINT64 l_qwCount = 0; + tUINT8 l_pBuffer[256] = {0}; + + l_cFile.Open("./ABC.txt", IFile::ECREATE | IFile::ESHARE_WRITE); + + l_qwCount = l_cFile.Write(l_pHeader, LENGTH(l_pHeader), FALSE); + l_qwCount = l_cFile.Write((tUINT8*)l_pText, LENGTH(l_pText) - 1, TRUE); + + l_qwCount = l_cFile.Get_Size(); + + l_cFile.Set_Position(0); + + l_qwCount = l_cFile.Read(l_pBuffer, LENGTH(l_pBuffer)); + + l_cFile.Close(TRUE); +*/ diff --git a/p7lib/Shared/Platforms/Linux_x86/PFileSystem.h b/p7lib/Shared/Platforms/Linux_x86/PFileSystem.h new file mode 100644 index 0000000..c4d992b --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PFileSystem.h @@ -0,0 +1,362 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PFILESYSTEM_H +#define PFILESYSTEM_H + +#include +#include +#include +#include +#include +#include + +class CFSYS +{ +public: + //////////////////////////////////////////////////////////////////////////// + //Directory_Exists + static tBOOL Directory_Exists(const tACHAR *i_pPath) + { + struct stat l_sStat; + l_sStat.st_mode = 0; + if (0 == stat(i_pPath, &l_sStat)) + { + if (0 != (l_sStat.st_mode & S_IFDIR)) + { + return TRUE; + } + } + + return FALSE; + }//Directory_Exists + + + //////////////////////////////////////////////////////////////////////////// + //Directory_Create + static tBOOL Directory_Create(const tACHAR *i_pDir) + { + if (NULL == i_pDir) + { + return FALSE; + } + + char *l_pDir = (char *)malloc(strlen(i_pDir) + 1); + char *l_pIter = l_pDir; + + if (NULL == l_pDir) + { + return FALSE; + } + + strcpy(l_pDir, i_pDir); + while (*l_pIter) + { + if ('/' == (*l_pIter)) + { + *l_pIter = 0; + + if ( (FALSE == CFSYS::Directory_Exists(l_pDir)) + && (l_pIter != l_pDir) + ) + { + mkdir(l_pDir, S_IRWXU | S_IRWXG | S_IROTH); + } + + *l_pIter = '/'; + } + + l_pIter++; + } + + free(l_pDir); + l_pDir = NULL; + + mkdir(i_pDir, S_IRWXU | S_IRWXG | S_IROTH); + + return Directory_Exists((tACHAR*)i_pDir); + }//Directory_Create + + + //////////////////////////////////////////////////////////////////////////// + //Directory_Delete + static tBOOL Directory_Delete(const tACHAR *i_pDir) + { + if (NULL == i_pDir) + { + return FALSE; + } + + return (0 == rmdir(i_pDir)); + }//Directory_Delete + + //////////////////////////////////////////////////////////////////////////// + //File_Exists + static tBOOL File_Exists(const tACHAR * i_pFileName) + { + struct stat l_sStat; + l_sStat.st_mode = 0; + if (0 == stat(i_pFileName, &l_sStat)) + { + if (0 != (l_sStat.st_mode & S_IFREG)) + { + return TRUE; + } + } + + return FALSE; + }//File_Exists + + + //////////////////////////////////////////////////////////////////////////// + // Enumerate_Files + static void Enumerate_Files(CBList *i_pDll_List, + CWString *i_pDirectory, + const char *i_pMask, //for example L"*.so" + tUINT32 i_dwDepth = 0xFFFFFFul + ) + { + tUINT32 l_dwLength = i_pDirectory->Length(); + + if ( (NULL == i_pDll_List) + || (NULL == i_pDirectory) + || (NULL == i_pMask) + ) + { + return; + } + + DIR *l_pDir = opendir(i_pDirectory->Get()); + dirent *l_pDir_Entry = 0; + + if (!l_pDir) + { + return; + } + + while ((l_pDir_Entry = readdir(l_pDir)) != 0) + { + if (DT_REG == l_pDir_Entry->d_type) + { + if (0 == fnmatch(i_pMask, l_pDir_Entry->d_name, FNM_NOESCAPE | FNM_CASEFOLD)) + { + CWString *i_pFile = new CWString(); + if (i_pFile) + { + i_pFile->Set(i_pDirectory->Get()); + i_pFile->Append(2, L"/", l_pDir_Entry->d_name); + i_pDll_List->Add_After(i_pDll_List->Get_Last(), i_pFile); + } + } + } + else if ( (DT_DIR == l_pDir_Entry->d_type) + && (0 != PStrCmp(l_pDir_Entry->d_name, ".")) + && (0 != PStrCmp(l_pDir_Entry->d_name, "..")) + && (i_dwDepth) + ) + { + i_pDirectory->Append(2, L"/", l_pDir_Entry->d_name); + Enumerate_Files(i_pDll_List, i_pDirectory, i_pMask, i_dwDepth - 1); + i_pDirectory->Trim(l_dwLength); + } + } + + closedir(l_pDir); + l_pDir = 0; + + }// Enumerate_Files + + + //////////////////////////////////////////////////////////////////////////// + // Enumerate_Dirs + static void Enumerate_Dirs(CBList *io_pList, const tXCHAR *i_pRoot) + { + if (NULL == io_pList) + { + return; + } + + if (!i_pRoot) + { + i_pRoot = "/"; + } + + DIR *l_pDir = opendir(i_pRoot); + dirent *l_pDir_Entry = 0; + + if (!l_pDir) + { + return; + } + + while ((l_pDir_Entry = readdir(l_pDir)) != 0) + { + if ( (DT_DIR == l_pDir_Entry->d_type) + && (0 != PStrCmp(l_pDir_Entry->d_name, ".")) + && (0 != PStrCmp(l_pDir_Entry->d_name, "..")) + ) + { + CWString *i_pFile = new CWString(); + if (i_pFile) + { + i_pFile->Set(i_pRoot); + i_pFile->Append(2, "/", l_pDir_Entry->d_name); + io_pList->Add_After(io_pList->Get_Last(), i_pFile); + } + } + } + + closedir(l_pDir); + l_pDir = 0; + }// Enumerate_Dirs + + //////////////////////////////////////////////////////////////////////////// + //Get_File_Size + static tUINT64 Get_File_Size(const tACHAR *i_pFile) + { + struct stat l_sStat; + l_sStat.st_size = 0; + if (0 == stat(i_pFile, &l_sStat)) + { + return (tUINT64)l_sStat.st_size; + } + + return 0; + }//Get_File_Size + + //////////////////////////////////////////////////////////////////////////// + //Get_Version + static tUINT64 Get_Version(const char *i_pFile) + { + UNUSED_ARG(i_pFile); + return 0ull; + }//Get_Version + + +// //////////////////////////////////////////////////////////////////////////// +// //Get_Process_Directory +// static BOOL Get_Process_Directory(CWString *o_pDirectory) +// { +// BOOL l_bReturn = FALSE; +// DWORD l_dwLength = 4096; + +// if ( (NULL == o_pDirectory) +// || (FALSE == o_pDirectory->Realloc(l_dwLength)) +// ) +// { +// return l_bReturn; +// } + +// if (0 != GetModuleFileNameW(GetModuleHandleW(NULL), +// o_pDirectory->Get(), +// o_pDirectory->Max_Length()) +// ) +// { +// wchar_t *l_pExe_Name = NULL; + +// if ( (l_pExe_Name = wcsrchr(o_pDirectory->Get(), L'\\')) +// || (l_pExe_Name = wcsrchr(o_pDirectory->Get(), L'/')) +// ) +// { +// o_pDirectory->Trim((DWORD)(l_pExe_Name - o_pDirectory->Get())); +// l_bReturn = TRUE; +// } +// } + +// return l_bReturn; +// }//Get_Process_Directory + + //////////////////////////////////////////////////////////////////////////// + //Delete_File + static tBOOL Delete_File(const char *i_pFile_Name) + { + if (NULL == i_pFile_Name) + { + return FALSE; + } + + return (0 == remove(i_pFile_Name)); + }//Delete_File + + //////////////////////////////////////////////////////////////////////////// + //GetUserDirectory + static tBOOL GetUserDirectory(CWString *o_pPath) + { + if ( (NULL == o_pPath) + || (FALSE == o_pPath->Realloc(4096)) + ) + { + return TRUE; + } + + struct passwd *pw = getpwuid(getuid()); + + if (!pw) + { + return FALSE; + } + + o_pPath->Set(pw->pw_dir); + return TRUE; + } + + + //////////////////////////////////////////////////////////////////////////// + //GetUserDirectory + static tBOOL GetDirectoryParent(CWString &i_rChild, CWString &o_rParent) + { + o_rParent.Set(i_rChild.Get()); + size_t l_szDir = o_rParent.Length(); + tXCHAR *l_pDir = o_rParent.Get(); + + //cut trailing '/' or '\' + while ( (l_szDir > 1) + && (TM('/') == l_pDir[l_szDir - 1]) + ) + { + l_pDir[--l_szDir] = 0; + } + + tXCHAR *l_pTemp = strrchr(l_pDir, TM('/')); + + if (!l_pTemp) + { + o_rParent.Set(TM("")); + return TRUE; + } + + l_pTemp++; + *l_pTemp = 0; + l_pTemp--; + + //removing duplicates of '/' + while ( (TM('/') == *l_pTemp) + && (l_pTemp > l_pDir) + ) + { + *l_pTemp = 0; + l_pTemp--; + } + + return (*l_pDir) ? TRUE : FALSE; + } + +}; + + +#endif //PFILESYSTEM_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PJournal.h b/p7lib/Shared/Platforms/Linux_x86/PJournal.h new file mode 100644 index 0000000..92be7b0 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PJournal.h @@ -0,0 +1,266 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PJOURNAL_H +#define PJOURNAL_H + +//#include +//#include +//#include +//#include +//#include //-pthread +//#include +//#include "Atomic.hpp" +//#include "Lock.hpp" +//#include "PTypes.hpp" +//#include "GTypes.hpp" +//#include "IJournal.hpp" + + +//////////////////////////////////////////////////////////////////////////////// +class CJournal + : public IJournal //virtual +{ + volatile tINT32 m_iRCnt; + tLOCK m_hCS; + tUINT64 m_pCount[IJournal::eLEVEL_COUNT]; + IJournal::eLevel m_eVerbosity; + tUINT32 m_pLength; + tXCHAR *m_pBuffer; + tXCHAR m_pName[IJournal::eLEVEL_COUNT][16]; +public: + //////////////////////////////////////////////////////////////////////////// + CJournal() + : m_iRCnt(1) + , m_eVerbosity(IJournal::eLEVEL_WARNING) + , m_pLength(8192) + { + LOCK_CREATE(m_hCS); + + for (tUINT32 l_dwI = 0; l_dwI < IJournal::eLEVEL_COUNT; l_dwI++) + { + m_pName[l_dwI][0] = 0; + m_pCount[l_dwI] = 0ULL; + } + + strcpy(m_pName[IJournal::eLEVEL_TRACE], "TRACE: "); + strcpy(m_pName[IJournal::eLEVEL_DEBUG], "DEBUG: "); + strcpy(m_pName[IJournal::eLEVEL_INFO], "INFO : "); + strcpy(m_pName[IJournal::eLEVEL_WARNING], "WARN.: "); + strcpy(m_pName[IJournal::eLEVEL_ERROR], "ERROR: "); + strcpy(m_pName[IJournal::eLEVEL_CRITICAL], "CRIT.: "); + } + + //////////////////////////////////////////////////////////////////////////// + virtual ~CJournal() + { + if (m_pBuffer) + { + delete [] m_pBuffer; + m_pBuffer = NULL; + } + + //if (m_iRCnt) + //{ + // printf("Error: CJournal reference counter is not 0"); + //} + LOCK_DESTROY(m_hCS); + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Initialize(const tXCHAR *i_pName) + { + UNUSED_ARG(i_pName); + + if (m_pBuffer) + { + return TRUE; + } + + m_pBuffer = new tXCHAR[m_pLength]; + + return m_pBuffer ? TRUE : FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + void Set_Verbosity(IJournal::eLevel i_eVerbosity) + { + LOCK_ENTER(m_hCS); + m_eVerbosity = i_eVerbosity; + LOCK_EXIT(m_hCS); + } + + //////////////////////////////////////////////////////////////////////////// + IJournal::eLevel Get_Verbosity() + { + IJournal::eLevel l_eReturn; + + LOCK_ENTER(m_hCS); + l_eReturn = m_eVerbosity; + LOCK_EXIT(m_hCS); + + return l_eReturn; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Log(IJournal::eLevel i_eType, + IJournal::hModule i_hModule, + const char *i_pFile, + const char *i_pFunction, + tUINT32 i_dwLine, + const tXCHAR *i_pFormat, + ... + ) + { + UNUSED_ARG(i_hModule); + UNUSED_ARG(i_pFile); + tBOOL l_bReturn = TRUE; + time_t l_tNow = time(NULL); + struct tm *l_pTime = localtime(&l_tNow); + struct timespec l_sTime = {0, 0}; + int l_iRes = 0; + int l_iOffs = 0; + tUINT64 l_qwMSec = 0; + + LOCK_ENTER(m_hCS); + + if ( (i_eType < m_eVerbosity) + || (NULL == m_pBuffer) + || (i_eType >= IJournal::eLEVEL_COUNT) + ) + { + l_bReturn = FALSE; + goto l_lExit; + } + + m_pCount[i_eType] ++; + + l_iRes = snprintf(m_pBuffer + l_iOffs, + m_pLength - l_iOffs, + "[%s] : [%d]\n", + i_pFunction, + (int)i_dwLine + ); + if (0 <= l_iRes) + { + l_iOffs += l_iRes; + } + + clock_gettime(CLOCK_MONOTONIC, &l_sTime); + + l_qwMSec = l_sTime.tv_sec; + l_qwMSec *= 1000; + l_qwMSec += l_sTime.tv_nsec/1000000; + + l_iRes = snprintf(m_pBuffer + l_iOffs, + m_pLength - l_iOffs, + "%04d.%02d.%02d %02d:%02d:%02d.%03d: %s: ", + l_pTime->tm_year + 1900, + l_pTime->tm_mon + 1, + l_pTime->tm_mday, + l_pTime->tm_hour, + l_pTime->tm_min, + l_pTime->tm_sec, + (int)(l_qwMSec % 1000), + m_pName[i_eType] + ); + if (0 <= l_iRes) + { + l_iOffs += l_iRes; + } + + va_list l_pVA; + va_start(l_pVA, i_pFormat); + vsnprintf(m_pBuffer + l_iOffs, m_pLength - l_iOffs, i_pFormat, l_pVA); + va_end(l_pVA); + + //std::cout << m_pBuffer << "\n"; + printf(m_pBuffer, 0); //0 to close warning from G++ + printf("\n"); + + + l_lExit: + LOCK_EXIT(m_hCS); + return l_bReturn; + } + + //////////////////////////////////////////////////////////////////////////// + tUINT64 Get_Count(IJournal::eLevel i_eType) + { + tUINT64 l_qwReturn = 0ULL; + + if (i_eType >= IJournal::eLEVEL_COUNT) + { + return 0ULL; + } + + LOCK_ENTER(m_hCS); + l_qwReturn = m_pCount[i_eType]; + LOCK_EXIT(m_hCS); + + return l_qwReturn; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Register_Thread(const tXCHAR *i_pName, tUINT32 i_dwThreadId) + { + UNUSED_ARG(i_pName); + UNUSED_ARG(i_dwThreadId); + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Unregister_Thread(tUINT32 i_dwThreadId) + { + UNUSED_ARG(i_dwThreadId); + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Register_Module(const tXCHAR *i_pName, IJournal::hModule *o_hModule) + { + UNUSED_ARG(i_pName); + if (o_hModule) + { + *o_hModule = NULL; + } + + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + tINT32 Add_Ref() + { + return ATOMIC_INC(&m_iRCnt); + } + + //////////////////////////////////////////////////////////////////////////// + tINT32 Release() + { + volatile tINT32 l_iReturn = ATOMIC_DEC(&m_iRCnt); + + if (0 >= l_iReturn) + { + delete this; + } + + return l_iReturn; + } +}; + +#endif //PJOURNAL_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PLock.h b/p7lib/Shared/Platforms/Linux_x86/PLock.h new file mode 100644 index 0000000..c4c3351 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PLock.h @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PLOCK_H +#define PLOCK_H + +#include + +/////////////////////////////////////////////////////////////////////////////// +typedef pthread_mutex_t tLOCK; + + +#define LOCK_CREATE(i_Lock) {\ + pthread_mutexattr_t l_sAttr;\ + memset(&l_sAttr, 0, sizeof(pthread_mutexattr_t));\ + pthread_mutexattr_init(&l_sAttr);\ + pthread_mutexattr_settype(&l_sAttr,\ + PTHREAD_MUTEX_RECURSIVE);\ + pthread_mutex_init(&i_Lock, &l_sAttr);\ + pthread_mutexattr_destroy(&l_sAttr);\ + }\ + + +#define LOCK_DESTROY(i_Lock) pthread_mutex_destroy(&i_Lock) + +#define LOCK_ENTER(i_Lock) pthread_mutex_lock(&i_Lock) +#define LOCK_EXIT(i_Lock) pthread_mutex_unlock(&i_Lock) +#define LOCK_TRY(i_Lock) ((0 == pthread_mutex_trylock(&i_Lock)) ? TRUE : FALSE) + +#endif //PLOCK_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PMEvent.h b/p7lib/Shared/Platforms/Linux_x86/PMEvent.h new file mode 100644 index 0000000..e378252 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PMEvent.h @@ -0,0 +1,469 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PMEVENT_H +#define PMEVENT_H + +#include + +// Infinite timeout +#define INFINITE 0xFFFFFFFF + +//#define PMEVENT_COND_VARIABLE + +//////////////////////////////////////////////////////////////////////////////// +//CMEvent - class designed to avoid problem of "wait" POSIX functions. They are +// based on abs. time and they are affected by system time changes. +class CMEvent + : public IMEvent //virtual +{ + struct sEvent + { + volatile tINT32 iCounter; + eMEvent_Type eType; + tUINT32 dwIdx; + sEvent *pNext; + }; + + pthread_mutex_t m_sMutex; + +#ifdef PMEVENT_COND_VARIABLE + pthread_cond_t m_sCV; +#else + sem_t m_sSem; +#endif + + tUINT8 m_bCount; + tBOOL m_bInit; + tBOOL m_bError; + sEvent *m_pEvents; + sEvent *m_pEvent_Cur; + tINT32 m_iSignals; +public: + //////////////////////////////////////////////////////////////////////////// + //CMEvent + CMEvent() + : m_bCount(0) + , m_bInit(FALSE) + , m_bError(FALSE) + , m_pEvents(NULL) + , m_pEvent_Cur(NULL) + , m_iSignals(0) + { + }//CMEvent + + + //////////////////////////////////////////////////////////////////////////// + //~CMEvent + virtual ~CMEvent() + { + if (m_bInit) + { + pthread_mutex_destroy(&m_sMutex); + +#ifdef PMEVENT_COND_VARIABLE + pthread_cond_destroy(&m_sCV); +#else + sem_destroy(&m_sSem); +#endif + + } + + Cleanup(); + + m_bCount = 0; + }//~CMEvent + + + //////////////////////////////////////////////////////////////////////////// + //Init + tBOOL Init(tUINT8 i_bCount, ...) + { + va_list l_pVA; + tUINT8 l_bIDX = 0; + tBOOL l_bCA = FALSE; + tBOOL l_bSig = FALSE; + tBOOL l_bMutex = FALSE; + pthread_condattr_t l_sCA; + + + if ( (TRUE == m_bInit) + || (TRUE == m_bError) + || (0 >= i_bCount) + ) + { + return FALSE; + } + + +#ifdef PMEVENT_COND_VARIABLE + //////////////////////////////////////////////////////////////////////// + //initialize Cond.Variable + clockid_t l_iClock = CLOCK_REALTIME; + + if (0 != pthread_condattr_init(&l_sCA)) + { + goto l_lExit; //error + } + else + { + l_bCA = TRUE; + } + + //#ifdef __USE_XOPEN2K + if (0 != pthread_condattr_setclock(&l_sCA, CLOCK_MONOTONIC)) + { + goto l_lExit; //error + } + + if ( (0 != pthread_condattr_getclock(&l_sCA, &l_iClock)) + || (CLOCK_MONOTONIC != l_iClock) + ) + { + goto l_lExit; //error + } + //#else + //#endif + + if (0 != pthread_cond_init(&m_sCV, &l_sCA)) + { + goto l_lExit; //error + } + else + { + l_bSig = TRUE; + } +#else + //////////////////////////////////////////////////////////////////////// + //initialize semaphore + if (0 != sem_init(&m_sSem, 0, 0)) + { + goto l_lExit; //error + } + else + { + l_bSig = TRUE; + } +#endif + + + //////////////////////////////////////////////////////////////////////// + //initialize mutex + if (0 != pthread_mutex_init(&m_sMutex, NULL)) + { + m_bError = TRUE; + goto l_lExit; + } + else + { + l_bMutex = TRUE; + } + + //////////////////////////////////////////////////////////////////////// + //initialize events structure + m_pEvents = new sEvent[i_bCount]; + if (NULL == m_pEvents) + { + goto l_lExit; + } + + memset(m_pEvents, 0, sizeof(sEvent) * i_bCount); + + m_pEvent_Cur = &m_pEvents[0]; + + va_start(l_pVA, i_bCount); + while (l_bIDX < i_bCount) + { + m_pEvents[l_bIDX].eType = (eMEvent_Type)va_arg(l_pVA, /*eMEvent_Type*/int); + m_pEvents[l_bIDX].iCounter = 0; + m_pEvents[l_bIDX].dwIdx = l_bIDX; + + //make round trip links + if ((l_bIDX + 1) < i_bCount) + { + m_pEvents[l_bIDX].pNext = &m_pEvents[l_bIDX + 1]; + } + else + { + m_pEvents[l_bIDX].pNext = &m_pEvents[0]; + } + + l_bIDX++; + } + + va_end(l_pVA); + + m_bInit = TRUE; + m_bCount = i_bCount; + + l_lExit: + if (l_bCA) + { + pthread_condattr_destroy(&l_sCA); + } + + if (FALSE == m_bInit) + { + m_bError = TRUE; + + if (l_bMutex) + { + pthread_mutex_destroy(&m_sMutex); + } + + if (l_bSig) + { +#ifdef PMEVENT_COND_VARIABLE + pthread_cond_destroy(&m_sCV); +#else + sem_destroy(&m_sSem); +#endif + } + + Cleanup(); + } + + return m_bInit; + }//Init + + + //////////////////////////////////////////////////////////////////////////// + //Set + tBOOL Set(tUINT32 i_dwID) + { + if ( (i_dwID >= m_bCount) + || (FALSE == m_bInit) + ) + { + return FALSE; + } + + pthread_mutex_lock(&m_sMutex); + + m_iSignals++; + m_pEvents[i_dwID].iCounter ++; + +#ifdef PMEVENT_COND_VARIABLE + pthread_cond_signal(&m_sCV); +#else + sem_post(&m_sSem); +#endif + + pthread_mutex_unlock(&m_sMutex); + + return TRUE; + }//Set + + + //////////////////////////////////////////////////////////////////////////// + //Clr + tBOOL Clr(tUINT32 i_dwID) + { + tBOOL l_bReturn = FALSE; + if ( (i_dwID >= m_bCount) + || (EMEVENT_SINGLE_MANUAL != m_pEvents[i_dwID].eType) + ) + { + return l_bReturn; + } + + pthread_mutex_lock(&m_sMutex); + + if (m_pEvents[i_dwID].iCounter) + { + m_iSignals --; + m_pEvents[i_dwID].iCounter --; + + sem_trywait(&m_sSem); //decrease semaphore + + l_bReturn = TRUE; + } + + pthread_mutex_unlock(&m_sMutex); + + return l_bReturn; + }//Clr + + + //////////////////////////////////////////////////////////////////////////// + //Wait + tUINT32 Wait() + { + tUINT32 l_dwReturn = MEVENT_TIME_OUT; + + //////////////////////////////////////////////////////////////////////// + //LOCK + +#ifdef PMEVENT_COND_VARIABLE + int l_iCV_Res = 0; + + pthread_mutex_lock(&m_sMutex); + + while (0 == m_iSignals) + { + l_iCV_Res = pthread_cond_wait(&m_sCV, &m_sMutex); + if (0 != l_iCV_Res) + { + break; + } + } + + l_dwReturn = Get_Signal(); + + pthread_mutex_unlock(&m_sMutex); +#else + sem_wait(&m_sSem); + + pthread_mutex_lock(&m_sMutex); + l_dwReturn = Get_Signal(); + pthread_mutex_unlock(&m_sMutex); +#endif + + + //UNLOCK + //////////////////////////////////////////////////////////////////////// + + return l_dwReturn; + }//Wait + + + //////////////////////////////////////////////////////////////////////////// + //Wait + tUINT32 Wait(tUINT32 i_dwMSec) + { + tUINT64 l_qwNano = (tUINT64)i_dwMSec * 1000000ULL; + tUINT32 l_dwReturn = MEVENT_TIME_OUT; + struct timespec l_sTime = {0, 0}; + + //////////////////////////////////////////////////////////////////////// + //LOCK + +#ifdef PMEVENT_COND_VARIABLE + int l_iRes = 0; + pthread_mutex_lock(&m_sMutex); + clock_gettime(CLOCK_MONOTONIC, &l_sTime); + + l_qwNano += l_sTime.tv_nsec; + l_sTime.tv_sec += static_cast<__time_t>(l_qwNano / 1000000000ULL); + l_sTime.tv_nsec = static_cast(l_qwNano % 1000000000ULL); + + while (0 == m_iSignals) + { + //ETIMEDOUT + l_iRes = pthread_cond_timedwait(&m_sCV, &m_sMutex, &l_sTime); + if (0 != l_iRes) + { + break; + } + } + + l_dwReturn = Get_Signal(); + pthread_mutex_unlock(&m_sMutex); +#else + if (0 == i_dwMSec) + { + if (0 == sem_trywait(&m_sSem)) + { + pthread_mutex_lock(&m_sMutex); + l_dwReturn = Get_Signal(); + pthread_mutex_unlock(&m_sMutex); + } + } + else + { + clock_gettime(CLOCK_REALTIME, &l_sTime); + + l_qwNano += l_sTime.tv_nsec; + l_sTime.tv_sec += static_cast(l_qwNano/1000000000ULL); + l_sTime.tv_nsec = static_cast(l_qwNano%1000000000ULL); + + if (0 == sem_timedwait(&m_sSem, &l_sTime)) + { + pthread_mutex_lock(&m_sMutex); + l_dwReturn = Get_Signal(); + pthread_mutex_unlock(&m_sMutex); + } + } +#endif + + //UNLOCK + //////////////////////////////////////////////////////////////////////// + + return l_dwReturn; + }//Wait + +private: + //////////////////////////////////////////////////////////////////////////// + //Get_Signal + tUINT32 Get_Signal() + { + tUINT32 l_dwReturn = MEVENT_TIME_OUT; + + if (0 == m_iSignals) //if we register some signal + { + return l_dwReturn; + } + + sEvent *l_pStart = m_pEvent_Cur; + //we will walk through all events in attempt to find signal + do + { + m_pEvent_Cur = m_pEvent_Cur->pNext; + + if (m_pEvent_Cur->iCounter) + { + l_dwReturn = m_pEvent_Cur->dwIdx; + if (EMEVENT_SINGLE_MANUAL == m_pEvent_Cur->eType) + { + sem_post(&m_sSem); //return sem value to signal again + } + else + { + m_pEvent_Cur->iCounter --; + m_iSignals --; + } + + break; + } + + //if we do round trip + } while (l_pStart != m_pEvent_Cur); + + if (MEVENT_TIME_OUT == l_dwReturn) + { + //error: signal event wasn't found ! + m_iSignals --; + } + + return l_dwReturn; + }//Get_Signal + + + //////////////////////////////////////////////////////////////////////////// + //Cleanup + void Cleanup() + { + if (m_pEvents) + { + delete [] m_pEvents; + m_pEvents = NULL; + } + }//Cleanup +}; + +#endif //PMEVENT_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PPerformanceInfo.h b/p7lib/Shared/Platforms/Linux_x86/PPerformanceInfo.h new file mode 100644 index 0000000..cdd44c2 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PPerformanceInfo.h @@ -0,0 +1,72 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PPERFORMANCE_INFO_H +#define PPERFORMANCE_INFO_H + +#include "IPerformanceInfo.h" + +//////////////////////////////////////////////////////////////////////////////// +class CPerformanceInfo + : public IPerformanceInfo +{ + volatile tINT32 m_iRCnt; +public: + //////////////////////////////////////////////////////////////////////////// + CPerformanceInfo(const tXCHAR *i_pProcessName) + : m_iRCnt(1) + { + UNUSED_ARG(i_pProcessName); + } + + virtual ~CPerformanceInfo() + { + } + + tBOOL Refresh() + { + return TRUE; + } + + tINT64 Get(IPerformanceInfo::eCounter i_eCounter) + { + UNUSED_ARG(i_eCounter); + return 0; + } + + //////////////////////////////////////////////////////////////////////////// + tINT32 Add_Ref() + { + return ATOMIC_INC(&m_iRCnt); + } + + //////////////////////////////////////////////////////////////////////////// + tINT32 Release() + { + volatile tINT32 l_iReturn = ATOMIC_DEC(&m_iRCnt); + + if (0 >= l_iReturn) + { + delete this; + } + + return l_iReturn; + } +}; + +#endif //PPERFORMANCE_INFO_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PProcess.h b/p7lib/Shared/Platforms/Linux_x86/PProcess.h new file mode 100644 index 0000000..2f7154d --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PProcess.h @@ -0,0 +1,575 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PPROCESS_H +#define PPROCESS_H + +#include +#include +#include +#include +#include +#include //HZ macro ! +#include + +class CProc +{ +public: + /////////////////////////////////////////////////////////////////////////////// + //Get_ArgV + static tXCHAR **Get_ArgV(tINT32 *o_pCount) + { + const tUINT16 l_wLen = 4096; + tXCHAR *l_pBuffer = new tXCHAR[l_wLen]; + tXCHAR **l_pReturn = NULL; + int l_pFile = -1; + tINT32 l_iRead = -1; + tBOOL l_bNew = TRUE; + tINT32 l_iIDX = 0; + + if ( (NULL == l_pBuffer) + || (NULL == o_pCount) + ) + { + goto l_lblExit; + } + + l_pFile = open("/proc/self/cmdline", O_RDONLY); + + if (-1 == l_pFile) + { + goto l_lblExit; + } + + l_iRead = read(l_pFile, l_pBuffer, l_wLen * sizeof(tXCHAR)); + + if (0 >= l_iRead) + { + goto l_lblExit; + } + + //calculate count of items////////////////////////////////////////////////// + *o_pCount = 0; + for (tINT32 l_iI = 0; l_iI < l_iRead; l_iI++) + { + if ( (0 == l_pBuffer[l_iI]) + || ((l_iI + 1) == l_iRead) + ) + { + (*o_pCount) ++; + } + } + + if (0 >= *o_pCount) + { + goto l_lblExit; + } + + //allocate result/////////////////////////////////////////////////////////// + l_pReturn = new tXCHAR*[*o_pCount]; + + if (NULL == l_pReturn) + { + goto l_lblExit; + } + + //fill result/////////////////////////////////////////////////////////////// + l_bNew = TRUE; + for (tINT32 l_iI = 0; l_iI < l_iRead; l_iI++) + { + if (l_bNew) + { + l_pReturn[l_iIDX++] = &l_pBuffer[l_iI]; + l_bNew = FALSE; + } + + if (0 == l_pBuffer[l_iI]) + { + l_bNew = TRUE; + } + } + + l_lblExit: + + if (-1 != l_pFile) + { + close(l_pFile); + } + + if (NULL == l_pReturn) + { + if (l_pBuffer) + { + delete [] l_pBuffer; + l_pBuffer = NULL; + } + } + + return l_pReturn; + // return = CommandLineToArgvW(GetCommandLineW(), o_pCount); + }//Get_ArgV + + + /////////////////////////////////////////////////////////////////////////////// + //Get_ArgV + static tXCHAR **Get_ArgV(const tXCHAR *i_pCmdLine, tINT32 *o_pCount) + { + tINT32 l_iLen = 0;//strlen(i_pCmdLine); + tXCHAR *l_pBuffer = NULL;//new tXCHAR[l_iLen]; + tXCHAR **l_pReturn = NULL; + tBOOL l_bNew = TRUE; + tBOOL l_bStr = FALSE; + tINT32 l_iIDX = 0; + + if ( (NULL == i_pCmdLine) + || (NULL == o_pCount) + ) + { + goto l_lblExit; + } + + l_iLen = (tINT32)strlen(i_pCmdLine) + 1; + l_pBuffer = new tXCHAR[l_iLen]; + + if (NULL == l_pBuffer) + { + goto l_lblExit; + } + + for (tINT32 l_iI = 0; l_iI < l_iLen; l_iI++) + { + if (TM('\"') == i_pCmdLine[l_iI]) + { + l_bStr = ! l_bStr; + } + else + { + if ( (TM(' ') == i_pCmdLine[l_iI]) + && (!l_bStr) + ) + { + l_pBuffer[l_iIDX++] = 0; + } + else + { + l_pBuffer[l_iIDX++] = i_pCmdLine[l_iI]; + } + + } + } + + l_iLen = l_iIDX; + + //calculate count of items////////////////////////////////////////////////// + *o_pCount = 0; + for (tINT32 l_iI = 0; l_iI < l_iLen; l_iI++) + { + if ( (0 == l_pBuffer[l_iI]) + || ((l_iI + 1) == l_iLen) + ) + { + (*o_pCount) ++; + } + } + + if (0 >= *o_pCount) + { + goto l_lblExit; + } + + //allocate result/////////////////////////////////////////////////////////// + l_pReturn = new tXCHAR*[*o_pCount]; + + if (NULL == l_pReturn) + { + goto l_lblExit; + } + + //fill result/////////////////////////////////////////////////////////////// + l_bNew = TRUE; + l_iIDX = 0; + for (tINT32 l_iI = 0; l_iI < l_iLen; l_iI++) + { + if (l_bNew) + { + l_pReturn[l_iIDX++] = &l_pBuffer[l_iI]; + l_bNew = FALSE; + } + + if (0 == l_pBuffer[l_iI]) + { + l_bNew = TRUE; + } + } + + l_lblExit: + + return l_pReturn; + }//Get_ArgV + + + /////////////////////////////////////////////////////////////////////////////// + //Free_ArgV + static void Free_ArgV(tXCHAR **i_pArgV) + { + if (NULL == i_pArgV) + { + return; + } + + if (i_pArgV[0]) + { + delete [] i_pArgV[0]; + } + + delete [] i_pArgV; + //LocalFree(i_pArgV); + }//Free_ArgV + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Time() + //return a 64-bit value divided into 2 parts representing the number of + //100-nanosecond intervals since January 1, 1601 (UTC). + static tBOOL Get_Process_Time(tUINT32 *o_pHTime, tUINT32 *o_pLTime) + { + const int l_iLen = 8192; + char *l_pBuffer = new char[l_iLen]; + int l_iRead = 0; + int l_pFile = -1; + char *l_pIter = NULL; + long long l_llBtime = 0; + long long l_llStime = 0; + int l_iSscanf = 0; + tBOOL l_bResult = FALSE; + + if ( (NULL == l_pBuffer) + || (NULL == o_pHTime) + || (NULL == o_pLTime) + ) + { + goto l_lblExit; + } + + *o_pHTime = 0; + *o_pLTime = 0; + + //read global stat////////////////////////////////////////////////////////// + l_pFile = open("/proc/stat", O_RDONLY); + if (-1 == l_pFile) + { + goto l_lblExit; + } + + l_iRead = read(l_pFile, l_pBuffer, l_iLen); + close(l_pFile); + + if (0 >= l_iRead) + { + goto l_lblExit; + } + + if (l_iRead < l_iLen) + { + l_pBuffer[l_iRead -1] = 0; + } + else + { + l_pBuffer[l_iLen -1] = 0; + } + + //printf((char*)l_pBuffer, 0); + //printf("\nLen = %d\n", l_iRead); + + //get "btime" value///////////////////////////////////////////////////////// + { + const char l_pBtime[] = "btime "; + int l_iBLen = strlen(l_pBtime); + + l_pIter = l_pBuffer; + for (int l_iI = 0; l_iI < l_iRead; l_iI++) + { + if (0 == strncmp(l_pBtime, l_pIter, l_iBLen)) + { + l_iSscanf = sscanf(l_pIter + l_iBLen, "%lld", &l_llBtime); + break; + } + else + { + l_pIter++; + } + } + } + + if (0 >= l_iSscanf) + { + goto l_lblExit; + } + + //read process statistics/////////////////////////////////////////////////// + l_pFile = open("/proc/self/stat", O_RDONLY); + + if (-1 == l_pFile) + { + goto l_lblExit; + } + + l_iRead = read(l_pFile, l_pBuffer, l_iLen); + close(l_pFile); + + if (0 >= l_iRead) + { + goto l_lblExit; + } + + if (l_iRead < l_iLen) + { + l_pBuffer[l_iRead -1] = 0; + } + else + { + l_pBuffer[l_iLen -1] = 0; + } + + //get process start time//////////////////////////////////////////////////// + { + int l_iItem = 1; + l_pIter = l_pBuffer; + for (int l_iI = 0; l_iI < l_iRead; l_iI++) + { + if (' ' == *l_pIter) + { + if (21 == l_iItem) + { + l_iSscanf = sscanf(l_pIter, " %lld", &l_llStime); + break; + } + else + { + l_iItem ++; + } + } + + l_pIter++; + } + } + + if (0 >= l_iSscanf) + { + goto l_lblExit; + } + + //HZ defined in #include + l_llStime = l_llBtime * 10000000ull + (l_llStime * 10000000ull / HZ); + l_llStime += TIME_OFFSET_1601_1970; //defined in "PTime.h" + + *o_pHTime = (l_llStime >> 32); + *o_pLTime = (l_llStime & 0xFFFFFFFF); + + l_bResult = TRUE; + + l_lblExit: + if (l_pBuffer) + { + delete [] l_pBuffer; + l_pBuffer = NULL; + } + + return l_bResult; + }//Get_Process_Time() + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Name + static tBOOL Get_Process_Name(tACHAR *o_pName, tINT32 i_iMax_Len) + { + int l_iRead = 0; + char *l_pName = NULL; + char *l_pDst = o_pName; + tBOOL l_bReturn = FALSE; + + if ( (NULL == o_pName) + || (32 >= i_iMax_Len) + || (NULL == o_pName) + ) + { + goto l_lblExit; + } + + l_iRead = readlink("/proc/self/exe", o_pName, i_iMax_Len - 1); + if (0 >= l_iRead) + { + // I guess we're not running on the right version of unix + goto l_lblExit; + } + + if (l_iRead >= i_iMax_Len) + { + l_iRead = i_iMax_Len - 1; + } + + o_pName[l_iRead] = '\0'; + + l_pName = o_pName + l_iRead; + + while (l_pName != o_pName) + { + if ( ('/' == *l_pName) + || ('\\' == *l_pName) + ) + { + l_pName ++; + break; + } + else + { + l_pName --; + } + } + + while (*l_pName) + { + *l_pDst++=*l_pName++; + } + *l_pDst = 0; + + l_bReturn = TRUE; + + l_lblExit: + return l_bReturn; + }//Get_Process_Name + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Name + static tBOOL Get_Process_Name(tWCHAR *o_pName, tINT32 i_iMax_Len) + { + int l_iLen = 4096; + char *l_pBuffer = new char[l_iLen]; + tBOOL l_bReturn = FALSE; + + + if ( (l_pBuffer) + && (Get_Process_Name(l_pBuffer, l_iLen)) + ) + { + l_bReturn = TRUE; + Convert_UTF8_To_UTF16(l_pBuffer, o_pName, i_iMax_Len); + } + else + { + Convert_UTF8_To_UTF16("Unknown", o_pName, i_iMax_Len); + } + + if (l_pBuffer) + { + delete [] l_pBuffer; + l_pBuffer = NULL; + } + + return l_bReturn; + }//Get_Process_Name + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Path + static tBOOL Get_Process_Path(tXCHAR *o_pPath, tINT32 i_iMax_Len) + { + int l_iRead = 0; + tBOOL l_bReturn = FALSE; + + if ( (NULL == o_pPath) + || (32 >= i_iMax_Len) + ) + { + goto l_lblExit; + } + + l_iRead = readlink("/proc/self/exe", o_pPath, i_iMax_Len - 4); + if (0 >= l_iRead) + { + // I guess we're not running on the right version of unix + goto l_lblExit; + } + + if (l_iRead >= i_iMax_Len) + { + // buffer is too small + goto l_lblExit; + } + + o_pPath[l_iRead] = '\0'; + + while (l_iRead) + { + if ( ('/' == o_pPath[l_iRead]) + || ('\\' == o_pPath[l_iRead]) + ) + { + break; + } + else + { + o_pPath[l_iRead--] = 0; + } + } + + l_bReturn = TRUE; + + l_lblExit: + + if (TRUE != l_bReturn) + { + strcpy(o_pPath, "./"); + } + + return l_bReturn; + }//Get_Process_Path + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_ID + static tUINT32 Get_Process_ID() + { + return getpid(); + //return GetCurrentProcessId(); + }//Get_Process_ID + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Thread_Id + static tUINT32 Get_Thread_Id() + { + return (int32_t)syscall(SYS_gettid); + //return pthread_self(); + //return gettid(); + }//Get_Thread_Id + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Processor + static __forceinline tUINT32 Get_Processor() + { +#ifdef __ARM_ARCH_5TEJ__ + return 0; +#else + return sched_getcpu(); +#endif + }//Get_Processor +}; + +#endif //PPROCESS_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PProfiler.h b/p7lib/Shared/Platforms/Linux_x86/PProfiler.h new file mode 100644 index 0000000..f47e72e --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PProfiler.h @@ -0,0 +1,99 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "PTime.h" +#include "Ticks.h" + +class CTickHi +{ + tUINT64 m_qwCounter; + tUINT64 m_qwMarkIn; + tUINT64 m_qwMarkOut; + tUINT64 m_qwResolution; +public: + CTickHi() + { + m_qwMarkIn = 0ull; + m_qwMarkOut = 0ull; + m_qwCounter = 0ull; + m_qwResolution = GetPerformanceFrequency(); + + Reset(); + Start(); + } + + void Start() + { + m_qwMarkIn = GetPerformanceCounter(); + } + + void Stop() + { + m_qwMarkOut = GetPerformanceCounter(); + m_qwCounter += m_qwMarkOut - m_qwMarkIn; + } + + void Reset() + { + m_qwCounter = 0; + } + + //Second == 100 000; + tUINT32 Get() + { + return (tUINT32)(m_qwCounter * 100000ULL / m_qwResolution); + } +}; + +class CTickLow +{ + tUINT32 m_dwStart; + tUINT32 m_dwStop; +public: + CTickLow() + { + m_dwStart = 0; + m_dwStop = 0; + + Reset(); + Start(); + } + + void Start() + { + m_dwStart = GetTickCount(); + } + + void Stop() + { + m_dwStop = GetTickCount(); + } + + void Reset() + { + m_dwStop = 0; + } + + //frequency 1 000 per second + tUINT32 Get() + { + return CTicks::Difference(m_dwStop, m_dwStart); + } +}; diff --git a/p7lib/Shared/Platforms/Linux_x86/PShared.h b/p7lib/Shared/Platforms/Linux_x86/PShared.h new file mode 100644 index 0000000..49ae678 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PShared.h @@ -0,0 +1,639 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PSHARED_H +#define PSHARED_H + + +//////////////////////////////////////////////////////////////////////////////// +//Headers dependencies: +#include +#include // For O_* constants +#include +#include +#include // For mode constants + +#define SHARED_NAME_FORMAT_STRING "/P7_Type%d_PID%d_Text%s" +#define SHARED_NAME_LEN (strlen(SHARED_NAME_FORMAT_STRING) + 64) +#define SHARED_SEM_NULL SEM_FAILED + +//////////////////////////////////////////////////////////////////////////////// +//CShared +class CShared +{ + struct sShared + { + int iMFD; + sem_t *hSemaphore; + size_t szName; + char *pName; + char *pSemName; + char *pMemName; + }; + + enum eType + { + ETYPE_MUTEX = 0, + ETYPE_FILE , + ETYPE_MAX + }; + +public: + typedef sShared *hShared; + typedef sem_t *hSem; + + enum eLock + { + E_OK , + E_TIMEOUT , + E_ERROR , + E_NOT_EXISTS + }; + + + //////////////////////////////////////////////////////////////////////////// + //CShared::Create + static tBOOL Create(CShared::hShared *o_pHandle, + const tXCHAR *i_pName, + const tUINT8 *i_pData, + tUINT16 i_wSize + ) + { + hShared l_pShared = NULL; + tBOOL l_bResult = TRUE; + tBOOL l_bRelease = FALSE; + void *l_pBuffer = NULL; + + if ( (NULL == i_pName) + || (NULL == i_pData) + || (0 >= i_wSize) + || (NULL == o_pHandle) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_pShared = (hShared)malloc(sizeof(sShared)); + if (NULL == l_pShared) + { + l_bResult = FALSE; + goto l_lblExit; + } + + memset(l_pShared, 0, sizeof(sShared)); + l_pShared->hSemaphore = SHARED_SEM_NULL; + l_pShared->iMFD = -1; + + l_pShared->szName = strlen(i_pName) + SHARED_NAME_LEN; + l_pShared->pName = strdup(i_pName); + l_pShared->pSemName = (char*)malloc(l_pShared->szName); + l_pShared->pMemName = (char*)malloc(l_pShared->szName); + + if ( (NULL == l_pShared->pSemName) + || (NULL == l_pShared->pMemName) + || (NULL == l_pShared->pName) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////// + //create ssemaphore and own it + Create_Name(l_pShared->pSemName, l_pShared->szName, ETYPE_MUTEX, i_pName); + + l_pShared->hSemaphore = sem_open(l_pShared->pSemName, O_CREAT | O_EXCL, 0666, 0); + if (SHARED_SEM_NULL == l_pShared->hSemaphore) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_bRelease = TRUE; + + //////////////////////////////////////////////////////////////////////// + //share memory + Create_Name(l_pShared->pMemName, l_pShared->szName, ETYPE_FILE, i_pName); + + l_pShared->iMFD = shm_open(l_pShared->pMemName, + O_RDWR | O_CREAT | O_EXCL, + 0666 + ); + if (0 > l_pShared->iMFD) + { + l_bResult = FALSE; + goto l_lblExit; + } + + if (0 != ftruncate(l_pShared->iMFD, (off_t)i_wSize)) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_pBuffer = mmap(0, + (size_t)i_wSize, + PROT_READ | PROT_WRITE, + MAP_SHARED, + l_pShared->iMFD, + 0 + ); + + if ( (NULL == l_pBuffer) + || (MAP_FAILED == l_pBuffer) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + *o_pHandle = (CShared::hShared)l_pShared; + + memcpy(l_pBuffer, i_pData, (size_t)i_wSize); + + if (0 != munmap(l_pBuffer, (size_t)i_wSize)) + { + } + + + l_lblExit: + if (l_bRelease) + { + sem_post(l_pShared->hSemaphore); + } + + if (FALSE == l_bResult) + { + Close(l_pShared); + l_pShared = NULL; + + if (o_pHandle) + { + *o_pHandle = NULL; + } + } + + return l_bResult; + }//CShared::Create + + + //////////////////////////////////////////////////////////////////////////// + //Read + static tBOOL Read(const tXCHAR *i_pName, + void *o_pData, + tUINT16 i_wSize + ) + { + tBOOL l_bResult = TRUE; + size_t l_szName = 0; + char *l_pName = NULL; + void *l_pBuffer = NULL; + int l_iMFD = -1; + struct stat l_sStat; + + + if ( (NULL == i_pName) + || (NULL == o_pData) + || (0 >= i_wSize) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_szName = strlen(i_pName) + SHARED_NAME_LEN; + l_pName = (char*)malloc(l_szName); + + if (NULL == l_pName) + { + l_bResult = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //open shared memory object + Create_Name(l_pName, l_szName, ETYPE_FILE, i_pName); + + l_iMFD = shm_open(l_pName, O_RDONLY, 0444); + + if (0 > l_iMFD) + { + l_bResult = FALSE; + goto l_lblExit; + } + + memset(&l_sStat, 0, sizeof(l_sStat)); + if (-1 == fstat(l_iMFD, &l_sStat)) + { + l_bResult = FALSE; + goto l_lblExit; + } + + if ((size_t)l_sStat.st_size > (size_t)i_wSize) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_pBuffer = mmap(0, + (size_t)l_sStat.st_size, + PROT_READ, + MAP_SHARED, + l_iMFD, + 0 + ); + + if ( (NULL == l_pBuffer) + || (MAP_FAILED == l_pBuffer) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + memcpy(o_pData, l_pBuffer, (size_t)l_sStat.st_size); + + if (0 == munmap(l_pBuffer, (size_t)l_sStat.st_size)) + { + l_pBuffer = NULL; + } + + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (0 <= l_iMFD) + { + close(l_iMFD); + l_iMFD = -1; + } + + return l_bResult; + }//Read + + + //////////////////////////////////////////////////////////////////////////// + //Write + static tBOOL Write(const tXCHAR *i_pName, + const tUINT8 *i_pData, + tUINT16 i_wSize + ) + { + tBOOL l_bResult = TRUE; + size_t l_szName = 0; + char *l_pName = NULL; + void *l_pBuffer = NULL; + int l_iMFD = -1; + struct stat l_sStat; + + + if ( (NULL == i_pName) + || (NULL == i_pData) + || (0 >= i_wSize) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_szName = strlen(i_pName) + SHARED_NAME_LEN; + l_pName = (char*)malloc(l_szName); + + if (NULL == l_pName) + { + l_bResult = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //open shared memory object + Create_Name(l_pName, l_szName, ETYPE_FILE, i_pName); + + l_iMFD = shm_open(l_pName, O_RDWR, 0666); + + if (0 > l_iMFD) + { + l_bResult = FALSE; + goto l_lblExit; + } + + memset(&l_sStat, 0, sizeof(l_sStat)); + if (-1 == fstat(l_iMFD, &l_sStat)) + { + l_bResult = FALSE; + goto l_lblExit; + } + + if ((size_t)l_sStat.st_size < (size_t)i_wSize) + { + l_bResult = FALSE; + goto l_lblExit; + } + + l_pBuffer = mmap(0, + (size_t)l_sStat.st_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + l_iMFD, + 0 + ); + + if ( (NULL == l_pBuffer) + || (MAP_FAILED == l_pBuffer) + ) + { + l_bResult = FALSE; + goto l_lblExit; + } + + memcpy(l_pBuffer, i_pData, (size_t)i_wSize); + + if (0 == munmap(l_pBuffer, (size_t)l_sStat.st_size)) + { + l_pBuffer = NULL; + } + + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (0 <= l_iMFD) + { + close(l_iMFD); + l_iMFD = -1; + } + + return l_bResult; + }//Write + + + //////////////////////////////////////////////////////////////////////////// + //Lock + static eLock Lock(const tXCHAR *i_pName, CShared::hSem &o_rSem, tUINT32 i_dwTimeout_ms) + { + eLock l_eReturn = CShared::E_TIMEOUT; + size_t l_szName = 0; + char *l_pName = NULL; + const int l_i1ms = 1000; + tINT64 l_llWait = (tINT64)i_dwTimeout_ms * 1000LL; + sem_t *l_hSem = SHARED_SEM_NULL; + + o_rSem = SHARED_SEM_NULL; + + if (NULL == i_pName) + { + l_eReturn = CShared::E_ERROR; + goto l_lblExit; + } + + l_szName = strlen(i_pName) + SHARED_NAME_LEN; + l_pName = (char*)malloc(l_szName); + + if (NULL == l_pName) + { + l_eReturn = CShared::E_ERROR; + goto l_lblExit; + } + + + //////////////////////////////////////////////////////////////////////// + //open semaphore + Create_Name(l_pName, l_szName, ETYPE_MUTEX, i_pName); + + l_hSem = sem_open(l_pName, 0); + if (SHARED_SEM_NULL == l_hSem) + { + l_eReturn = CShared::E_NOT_EXISTS; + goto l_lblExit; + } + + l_eReturn = CShared::E_TIMEOUT; + + while (0 < l_llWait) + { + if (0 == sem_trywait(l_hSem)) + { + l_eReturn = CShared::E_OK; + break; + } + else + { + usleep(l_i1ms); //10 ms + l_llWait -= l_i1ms; + } + } + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (SHARED_SEM_NULL != l_hSem) + { + if (CShared::E_OK == l_eReturn) + { + o_rSem = l_hSem; + } + else + { + sem_close(l_hSem); + l_hSem = SHARED_SEM_NULL; + } + } + + return l_eReturn; + }//Lock + + //////////////////////////////////////////////////////////////////////////// + //UnLock + static eLock UnLock(CShared::hSem &io_rSem) + { + eLock l_eReturn = CShared::E_ERROR; + + if (SHARED_SEM_NULL == io_rSem) + { + l_eReturn = CShared::E_NOT_EXISTS; + goto l_lblExit; + } + + if (0 == sem_post(io_rSem)) + { + l_eReturn = CShared::E_OK; + } + + sem_close(io_rSem); + io_rSem = SHARED_SEM_NULL; + + l_lblExit: + return l_eReturn; + }//UnLock + + //////////////////////////////////////////////////////////////////////////// + //GetSemName + static const tXCHAR* GetName(hShared i_pShared) + { + if (NULL == i_pShared) + { + return FALSE; + } + + return i_pShared->pName; + } + + + //////////////////////////////////////////////////////////////////////////// + //Close + static tBOOL Close(hShared i_pShared) + { + if (NULL == i_pShared) + { + return FALSE; + } + + //if (SHARED_SEM_NULL != i_pShared->hSemaphore) + //{ + // sem_wait(i_pShared->hSemaphore); + //} + + if (0 <= i_pShared->iMFD) + { + close(i_pShared->iMFD); + i_pShared->iMFD = -1; + } + + if (i_pShared->pMemName) + { + shm_unlink(i_pShared->pMemName); + } + + if (SHARED_SEM_NULL != i_pShared->hSemaphore) + { + int l_iRes = -1; + l_iRes = sem_close(i_pShared->hSemaphore); + i_pShared->hSemaphore = SHARED_SEM_NULL; + UNUSED_ARG(l_iRes); + } + + if (i_pShared->pSemName) + { + sem_unlink(i_pShared->pSemName); + free(i_pShared->pSemName); + i_pShared->pSemName = NULL; + } + + if (i_pShared->pMemName) + { + free(i_pShared->pMemName); + i_pShared->pMemName = NULL; + } + + if (i_pShared->pName) + { + free(i_pShared->pName); + i_pShared->pName = NULL; + } + + i_pShared->szName = 0; + + free(i_pShared); + i_pShared = NULL; + + return TRUE; + }//Close + + //////////////////////////////////////////////////////////////////////////// + //UnLink + static tBOOL UnLink(const tXCHAR *i_pName) + { + tBOOL l_bReturn = TRUE; + size_t l_szName = 0; + char *l_pName = NULL; + + if (NULL == i_pName) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_szName = strlen(i_pName) + SHARED_NAME_LEN; + l_pName = (char*)malloc(l_szName); + + if (NULL == l_pName) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + Create_Name(l_pName, l_szName, ETYPE_MUTEX, i_pName); + if (0 != sem_unlink(l_pName)) + { + l_bReturn = FALSE; + } + + Create_Name(l_pName, l_szName, ETYPE_FILE, i_pName); + if (0 != shm_unlink(l_pName)) + { + l_bReturn = FALSE; + } + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + return l_bReturn; + }//UnLink + +private: + //////////////////////////////////////////////////////////////////////////// + //Create_Name + static tBOOL Create_Name(tXCHAR *o_pName, + size_t i_szName, + eType i_eType, + const tXCHAR *i_pPostfix + ) + { + if ( (NULL == o_pName) + || (16 >= i_szName) + || (ETYPE_MAX <= i_eType) + || (NULL == i_pPostfix) + ) + { + return FALSE; + } + + snprintf(o_pName, i_szName, SHARED_NAME_FORMAT_STRING, i_eType, getpid(), i_pPostfix); + + return TRUE; + }//Create_Name +}; + + +#endif //PSHARED_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PSharedLib.h b/p7lib/Shared/Platforms/Linux_x86/PSharedLib.h new file mode 100644 index 0000000..5783938 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PSharedLib.h @@ -0,0 +1,75 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef IPSHARED_LIB_H +#define IPSHARED_LIB_H + +#include "GTypes.h" + +#include "Length.h" +#include "PString.h" +#include "WString.h" +#include "SharedLib.h" +#include "PAtomic.h" +#include + +class CPSharedLib + : public CSharedLib +{ +protected: + void *m_pSo; + +public: + CPSharedLib(const tXCHAR *i_pPath) + : CSharedLib(i_pPath) + , m_pSo(NULL) + { + m_pSo = dlopen(i_pPath, RTLD_LAZY); + + if (m_pSo) + { + m_bState = TRUE; + } + } + + void *GetFunction(const tACHAR *i_pName) + { + dlerror(); /* Clear any existing error */ + + void* l_pReturn = (void*) (dlsym(m_pSo, i_pName)); + + if (NULL != dlerror()) + { + return NULL; + } + + return l_pReturn; + } + + virtual ~CPSharedLib() + { + if (m_pSo) + { + dlclose(m_pSo); + m_pSo = NULL; + } + } +}; + + +#endif //IPSHARED_LIB_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PSignal.h b/p7lib/Shared/Platforms/Linux_x86/PSignal.h new file mode 100644 index 0000000..84323f2 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PSignal.h @@ -0,0 +1,217 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PSIGNAL_H +#define PSIGNAL_H + +#include +#include +#include "signal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "ISignal.h" + +//Linux signal handling article: +//http://www.linuxprogrammingblog.com/all-about-linux-signals?page=show + +static stChContext g_stContext = {0}; + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Signal_Text +static __attribute__ ((unused)) const char *ChGetSignalText(int i_iSignal, siginfo_t* i_pSigInfo) +{ + if (i_iSignal == SIGBUS) + { + if (i_pSigInfo->si_code == BUS_ADRALN) { return "SIGBUS::BUS_ADRALN"; } + else if (i_pSigInfo->si_code == BUS_ADRERR) { return "SIGBUS::BUS_ADRERR"; } + else if (i_pSigInfo->si_code == BUS_OBJERR) { return "SIGBUS::BUS_OBJERR"; } + else { return "SIGBUS::"; } + } + else if (i_iSignal == SIGFPE) + { + if (i_pSigInfo->si_code == FPE_FLTDIV) { return "SIGFPE::FPE_FLTDIV"; } + else if (i_pSigInfo->si_code == FPE_FLTINV) { return "SIGFPE::FPE_FLTINV"; } + else if (i_pSigInfo->si_code == FPE_FLTOVF) { return "SIGFPE::FPE_FLTOVF"; } + else if (i_pSigInfo->si_code == FPE_FLTRES) { return "SIGFPE::FPE_FLTRES"; } + else if (i_pSigInfo->si_code == FPE_FLTSUB) { return "SIGFPE::FPE_FLTSUB"; } + else if (i_pSigInfo->si_code == FPE_FLTUND) { return "SIGFPE::FPE_FLTUND"; } + else if (i_pSigInfo->si_code == FPE_INTDIV) { return "SIGFPE::FPE_INTDIV"; } + else if (i_pSigInfo->si_code == FPE_INTOVF) { return "SIGFPE::FPE_INTOVF"; } + else { return "SIGFPE::"; } + } + else if (i_iSignal == SIGILL) + { + if (i_pSigInfo->si_code == ILL_BADSTK) { return "SIGILL::ILL_BADSTK"; } + else if (i_pSigInfo->si_code == ILL_COPROC) { return "SIGILL::ILL_COPROC"; } + else if (i_pSigInfo->si_code == ILL_ILLOPN) { return "SIGILL::ILL_ILLOPN"; } + else if (i_pSigInfo->si_code == ILL_ILLADR) { return "SIGILL::ILL_ILLADR"; } + else if (i_pSigInfo->si_code == ILL_ILLTRP) { return "SIGILL::ILL_ILLTRP"; } + else if (i_pSigInfo->si_code == ILL_PRVOPC) { return "SIGILL::ILL_PRVOPC"; } + else if (i_pSigInfo->si_code == ILL_PRVREG) { return "SIGILL::ILL_PRVREG"; } + else { return "SIGILL::"; } + } + else if (i_iSignal == SIGSEGV) + { + if (i_pSigInfo->si_code == SEGV_MAPERR) { return "SIGSEGV::SEGV_MAPERR"; } + else if (i_pSigInfo->si_code == SEGV_ACCERR){ return "SIGSEGV::SEGV_ACCERR"; } + else { return "SIGSEGV::"; } + } + + return "::"; +}//Get_Signal_Text + + +//////////////////////////////////////////////////////////////////////////////// +//ChHandler +static __attribute__ ((unused)) void ChHandler(int i_iSignal, + siginfo_t *i_pSigInfo, + void *i_pContext + ) +{ + UNUSED_ARG(i_pContext); + if (g_stContext.iProcessed) + { + return; + } + + g_stContext.iProcessed = 1; + + const char *l_pText = ChGetSignalText(i_iSignal, i_pSigInfo); + + if (g_stContext.pUserHandler) + { + g_stContext.pUserHandler((eCrashCode)(eCrashSignal + i_iSignal), l_pText, g_stContext.pUserContext); + } + + printf("Process has been terminated by signal {%s}\n", l_pText); +}//ChHandler + + +//////////////////////////////////////////////////////////////////////////////// +//ChInstall +static __attribute__ ((unused)) tBOOL ChInstallPrivate() +{ + struct sigaction l_sSignal; + struct sigaction l_sSignalPipe; + tBOOL l_bReturn = TRUE; + + //////////////////////////////////////////////////////////////////////////// + // installing signal handling ... + memset(&l_sSignalPipe, 0, sizeof(l_sSignalPipe)); + memset(&l_sSignal, 0, sizeof(l_sSignal)); + + //remove SIGPIPE signal, should be ignored + l_sSignalPipe.sa_handler = SIG_IGN; + sigemptyset(&l_sSignalPipe.sa_mask); + l_bReturn = (sigaction(SIGPIPE, &l_sSignalPipe, NULL) == 0); + + l_sSignal.sa_flags = SA_RESETHAND | SA_SIGINFO; + l_sSignal.sa_sigaction = &ChHandler; + sigemptyset(&l_sSignal.sa_mask); + + l_bReturn &= (sigaction(SIGILL, &l_sSignal, NULL) == 0); + l_bReturn &= (sigaction(SIGABRT, &l_sSignal, NULL) == 0); + l_bReturn &= (sigaction(SIGFPE, &l_sSignal, NULL) == 0); + l_bReturn &= (sigaction(SIGBUS, &l_sSignal, NULL) == 0); + l_bReturn &= (sigaction(SIGSEGV, &l_sSignal, NULL) == 0); + + if (!l_bReturn) + { + printf("ERROR: can't initialize signal handler"); + } + + return l_bReturn; +}//ChInstall + + + +//////////////////////////////////////////////////////////////////////////////// +//ChInstall +static __attribute__ ((unused)) tBOOL ChInstall() +{ + tBOOL l_bReturn = TRUE; + + if (g_stContext.iInstalled) + { + return FALSE; + } + + memset(&g_stContext, 0, sizeof(g_stContext)); + g_stContext.iProcessed = 0; + + l_bReturn = ChInstallPrivate(); + + if (l_bReturn) + { + g_stContext.iInstalled = 1; + } + else + { + printf("ERROR: can't initialize signal handler"); + } + + return l_bReturn; +}//ChInstall + + +//////////////////////////////////////////////////////////////////////////////// +//ChSetHandler +static __attribute__ ((unused)) tBOOL ChSetHandler(fnCrashHandler i_fnHandler) +{ + if (!g_stContext.iInstalled) + { + return FALSE; + } + + g_stContext.pUserHandler = i_fnHandler; + + return TRUE; +}//ChSetHandler + + + +//////////////////////////////////////////////////////////////////////////////// +//ChSetContext +static __attribute__ ((unused)) tBOOL ChSetContext(void *i_pContext) +{ + if (!g_stContext.iInstalled) + { + return FALSE; + } + + g_stContext.pUserContext = i_pContext; + + return TRUE; +}//ChSetContext + + +//////////////////////////////////////////////////////////////////////////////// +//ChUnInstall +static __attribute__ ((unused)) tBOOL ChUnInstall() +{ + return TRUE; +}//ChUnInstall + +#endif //PSIGNAL_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PSocket.h b/p7lib/Shared/Platforms/Linux_x86/PSocket.h new file mode 100644 index 0000000..f6b3aab --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PSocket.h @@ -0,0 +1,237 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PSOCKET_H +#define PSOCKET_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "AList.h" +#include + + +#ifdef __ARM_ARCH_5TEJ__ + #define SERVER_RECV_BUFFER_SIZE (0x200000) //2mb + #define SERVER_SEND_BUFFER_SIZE (0x40000) //256kb + + #define CLIENT_RECV_BUFFER_SIZE (0x4000) //16 kb + #define CLIENT_SEND_BUFFER_SIZE (0x10000) //64 kb +#else + #define SERVER_RECV_BUFFER_SIZE (0x200000) //2mb + #define SERVER_SEND_BUFFER_SIZE (0x40000) //256kb + + #define CLIENT_RECV_BUFFER_SIZE (0x40000) //256 kb + #define CLIENT_SEND_BUFFER_SIZE (0x40000) //256 kb +#endif + +typedef int tSOCKET; +//typedef SOCKET tSOCKET; + +typedef socklen_t tADDR_LEN; +//typedef int tADDR_LEN; + +typedef addrinfo tADDR_INFO; +//typedef addrinfoW tADDR_INFO; + + +#define INVALID_SOCKET_VAL (-1) + //(INVALID_SOCKET) + +#define CONNECTION_IN_PROGRESS (EINPROGRESS) + //(WSAEWOULDBLOCK) + + + + + +#define CLOSE_SOCKET(i_Socket) close(i_Socket) + //closesocket(m_hSocket); + + +#define GET_SOCKET_ERROR() errno + //WSAGetLastError(); + +#define SOCKET_ERROR (-1) + +#define GET_ADDR_INFO(i_Node, i_Service, i_Hints, o_Res) getaddrinfo(i_Node,\ + i_Service,\ + i_Hints,\ + o_Res) +//GetAddrInfoW + +#define FREE_ADDR_INFO(i_Info) freeaddrinfo(i_Info) +//FreeAddrInfoW + +//////////////////////////////////////////////////////////////////////////////// +//WSA_Init +static __attribute__ ((unused)) tBOOL WSA_Init() +{ + return TRUE; + + //WSADATA l_tWSA; + // + //if (0 != WSAStartup(MAKEWORD(1,1), &l_tWSA)) + //{ + // return FALSE; + //} + //return TRUE; +}//WSA_Init + + +//////////////////////////////////////////////////////////////////////////////// +//WSA_UnInit +static __attribute__ ((unused)) void WSA_UnInit() +{ + //WSACleanup(); +}//WSA_UnInit + +//////////////////////////////////////////////////////////////////////////////// +//PEnumIps +static __attribute__ ((unused)) tBOOL PEnumIps(CBList *io_pList) +{ + if (!io_pList) + { + return FALSE; + } + + io_pList->Clear(TRUE); + + struct ifaddrs *l_pIfAddr = NULL; + + if (-1 == getifaddrs(&l_pIfAddr)) + { + return FALSE; + } + + for (struct ifaddrs *l_pAddr = l_pIfAddr; l_pAddr != NULL; l_pAddr = l_pAddr->ifa_next) + { + if ( (l_pAddr->ifa_addr == NULL) + || ( (AF_INET != l_pAddr->ifa_addr->sa_family) + && (AF_INET6 != l_pAddr->ifa_addr->sa_family) + ) + ) + { + continue; + } + + sockaddr_storage *l_pNew = new sockaddr_storage; + if (AF_INET == l_pAddr->ifa_addr->sa_family) + { + memcpy(l_pNew, l_pAddr->ifa_addr, sizeof(sockaddr_in)); + } + else if (AF_INET6 == l_pAddr->ifa_addr->sa_family) + { + memcpy(l_pNew, l_pAddr->ifa_addr, sizeof(sockaddr_in6)); + } + else + { + memset(l_pNew, 0, sizeof(sockaddr_storage)); + } + + io_pList->Add_After(NULL, l_pNew); + } + + freeifaddrs(l_pIfAddr); + + return TRUE; +}//PEnumIps + + +//////////////////////////////////////////////////////////////////////////////// +//Print_SAddr +static __attribute__ ((unused)) tBOOL Print_SAddr(sockaddr *i_pAddress, XCHAR *o_pIP, tUINT32 i_dwLen) +{ + tBOOL l_bReturn = FALSE; + + if ( (NULL == i_pAddress) + || (NULL == o_pIP) + || (15 >= i_dwLen) + ) + { + return l_bReturn; + } + + if (AF_INET6 == i_pAddress->sa_family) + { + if (NULL != inet_ntop(i_pAddress->sa_family, + &((sockaddr_in6*)i_pAddress)->sin6_addr, + o_pIP, + i_dwLen + ) + ) + { + l_bReturn = TRUE; + } + } + else if (AF_INET == i_pAddress->sa_family) + { + if (NULL != inet_ntop(i_pAddress->sa_family, + &((sockaddr_in*)i_pAddress)->sin_addr, + o_pIP, + i_dwLen + ) + ) + { + l_bReturn = TRUE; + } + } + + //WSAAddressToString(i_pAddress, + // m_dwAddress_Size, + // NULL, + // l_pIP, + // &l_dwSize); + + return l_bReturn; +}//Print_SAddr + + +//////////////////////////////////////////////////////////////////////////////// +//Disable_PortUnreachable_ICMP +static __attribute__ ((unused)) tBOOL Disable_PortUnreachable_ICMP(tSOCKET i_hSocket) +{ + UNUSED_ARG(i_hSocket); + + //tUINT32 l_dwBytesReturned = 0; + //tBOOL l_bNewBehavior = FALSE; + //tUINT32 l_dwStatus = 0; + // + // + //l_dwStatus = WSAIoctl(m_hSocket, + // SIO_UDP_CONNRESET, + // &l_bNewBehavior, + // sizeof(l_bNewBehavior), + // NULL, + // 0, + // &l_dwBytesReturned, + // NULL, + // NULL + // ); + //return (SOCKET_ERROR == l_dwStatus) ? FALSE : TRUE; + + //don't know how to do it under Linux yet. + return TRUE; +}//Disable_PortUnreachable_ICMP + +#endif //PSOCKET_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PString.h b/p7lib/Shared/Platforms/Linux_x86/PString.h new file mode 100644 index 0000000..42fac77 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PString.h @@ -0,0 +1,245 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PSTRING_H +#define PSTRING_H + +#if !defined(PRINTF) + #if defined(UTF8_ENCODING) + #define PRINTF(...) printf(__VA_ARGS__) + #else + #define PRINTF(...) wprintf(__VA_ARGS__) + #endif +#endif + +#include +#include +#include +#include +#include "UTF.h" + +//////////////////////////////////////////////////////////////////////////////// +//PStrLen +static __attribute__ ((unused)) tUINT32 PStrLen(const tXCHAR *i_pText) +{ + return strlen(i_pText); +}//PStrLen + +//////////////////////////////////////////////////////////////////////////////// +//PStrCpy +static __attribute__ ((unused)) tXCHAR* PStrCpy(tXCHAR *i_pDst, + size_t i_szDst, + const tXCHAR *i_pSrc) +{ + UNUSED_ARG(i_szDst); + return strcpy(i_pDst, i_pSrc); +}//PStrLen + +//////////////////////////////////////////////////////////////////////////////// +//PWStrCpy +static inline tWCHAR *PWStrCpy(tWCHAR *i_pDst, + size_t i_szDst, + const tWCHAR *i_pSrc + ) +{ + while ( (*i_pSrc) + && (1 < i_szDst) + ) + { + *i_pDst = *i_pSrc; + i_pDst++; i_pSrc++; + i_szDst--; + } + + *i_pDst = 0; + + return i_pDst; +}//PStrLen + + +//////////////////////////////////////////////////////////////////////////////// +//PStrCpy +static __attribute__ ((unused)) tXCHAR* PStrNCpy(tXCHAR *i_pDst, + size_t i_szDst, + const tXCHAR *i_pSrc, + size_t i_pSrcMaxCount + ) +{ + UNUSED_ARG(i_szDst); + strncpy((char*)i_pDst, (char*)i_pSrc, i_pSrcMaxCount); + return i_pDst; +}//PStrLen + + +//////////////////////////////////////////////////////////////////////////////// +//PStrNCmp +static __attribute__ ((unused)) tINT32 PStrNCmp(const tXCHAR *i_pS1, + const tXCHAR *i_pS2, + size_t i_szLen + ) +{ + return strncmp(i_pS1, i_pS2, i_szLen); +}//PStrNCmp + + +//////////////////////////////////////////////////////////////////////////////// +//PStrNCmp +static __attribute__ ((unused)) tINT32 PStrNiCmp(const tXCHAR *i_pS1, + const tXCHAR *i_pS2, + size_t i_szLen + ) +{ + return strncasecmp(i_pS1, i_pS2, i_szLen); +}//PStrNCmp + + +//////////////////////////////////////////////////////////////////////////////// +//PStrNCmp +static __attribute__ ((unused)) tINT32 PStrICmp(const tXCHAR *i_pS1, + const tXCHAR *i_pS2 + ) +{ + return strcasecmp(i_pS1, i_pS2); +}//PStrNCmp + + +//////////////////////////////////////////////////////////////////////////////// +//PStrCmp +static __attribute__ ((unused)) tINT32 PStrCmp(const tXCHAR *i_pS1, + const tXCHAR *i_pS2 + ) +{ + return strcmp(i_pS1, i_pS2); +}//PStrCmp + +//////////////////////////////////////////////////////////////////////////////// +//PStrToInt +static __attribute__ ((unused)) tINT32 PStrToInt(const tXCHAR *i_pS1) +{ + return atoi(i_pS1); +}//PStrToInt + + +//////////////////////////////////////////////////////////////////////////////// +//PUStrLen +static __attribute__ ((unused)) tUINT32 PUStrLen(const tXCHAR *i_pText) +{ + return Get_UTF8_Length(i_pText); +}//PUStrLen + + + +//////////////////////////////////////////////////////////////////////////////// +//PUStrCpy +static __attribute__ ((unused)) void PUStrCpy(tWCHAR *i_pDst, + tUINT32 i_dwMax_Len, + const tXCHAR *i_pSrc) +{ + Convert_UTF8_To_UTF16(i_pSrc, i_pDst, i_dwMax_Len); + //wcscpy_s(i_pDst, i_dwMax_Len, i_pSrc); +}//PUStrCpy + + +/////////////////////////////////////////////////////////////////////////////// +//PSPrint +static __attribute__ ((unused)) tINT32 PSPrint(tXCHAR *o_pBuffer, + size_t i_szBuffer, + const tXCHAR *i_pFormat, + ... + ) +{ + va_list l_pVA; + int l_iReturn = 0; + + va_start(l_pVA, i_pFormat); + + l_iReturn = vsnprintf((char*)o_pBuffer, + i_szBuffer, + (char*)i_pFormat, + l_pVA); + + va_end(l_pVA); + + return (tINT32)l_iReturn; +}//PSPrint + + +/////////////////////////////////////////////////////////////////////////////// +//PStrDub +static __attribute__ ((unused)) tXCHAR *PStrDub(const tXCHAR *i_pStr) +{ + return strdup(i_pStr); +}//PStrDub + + +/////////////////////////////////////////////////////////////////////////////// +//PStrFreeDub +static __attribute__ ((unused)) void PStrFreeDub(tXCHAR *i_pStr) +{ + free(i_pStr); +}//PStrFreeDub + + +/////////////////////////////////////////////////////////////////////////////// +//PStrChr +static const __attribute__ ((unused)) tXCHAR *PStrChr(const tXCHAR * i_pStr, tXCHAR i_cCh) +{ + return strchr(i_pStr, i_cCh); +}//PStrChr + +/////////////////////////////////////////////////////////////////////////////// +//PStrChr +static __attribute__ ((unused)) tXCHAR *PStrChr(tXCHAR * i_pStr, tXCHAR i_cCh) +{ + return strchr(i_pStr, i_cCh); +}//PStrChr + + +/////////////////////////////////////////////////////////////////////////////// +//PStrrChr +static const __attribute__ ((unused)) tXCHAR *PStrrChr(const tXCHAR * i_pStr, const tXCHAR i_cCh) +{ + return strrchr(i_pStr, i_cCh); +}//PStrrChr + +/////////////////////////////////////////////////////////////////////////////// +//PStrrChr +static __attribute__ ((unused)) tXCHAR *PStrrChr(tXCHAR * i_pStr, tXCHAR i_cCh) +{ + return strrchr(i_pStr, i_cCh); +}//PStrrChr + + +/////////////////////////////////////////////////////////////////////////////// +//PVsnprintf +static __attribute__ ((unused)) int PVsnprintf(tXCHAR *o_pBuffer, + size_t i_szBuffer, + const tXCHAR *i_pFormat, + va_list i_pArgs) +{ + return vsnprintf(o_pBuffer, i_szBuffer, i_pFormat, i_pArgs); +}//PVsnprintf + + + +/////////////////////////////////////////////////////////////////////////////// +//PStrScan +#define PStrScan(i_pBuffer, i_pFormat, ...) sscanf(i_pBuffer, i_pFormat, __VA_ARGS__) + + +#endif //PSTRING_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PSystem.h b/p7lib/Shared/Platforms/Linux_x86/PSystem.h new file mode 100644 index 0000000..5cc3109 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PSystem.h @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PSYSTEM_H +#define PSYSTEM_H + +#include + +class CSys +{ +public: + /////////////////////////////////////////////////////////////////////////////// + //Get_Host_Name + static tBOOL Get_Host_Name(tWCHAR *o_pName, size_t i_szName) + { + const size_t l_szName = 256; + char l_pName[l_szName]; + + if (0 == gethostname(l_pName, l_szName)) + { + //If the null-terminated hostname is too large to fit, then the name + //is truncated, and no error is returned (but see NOTES below). + //POSIX.1-2001 says that if such truncation occurs, then it is + //unspecified whether the returned buffer includes a terminating + //null byte. + l_pName[l_szName-1] = 0; + } + else + { + strcpy(l_pName, "Unknown:Error"); + } + + Convert_UTF8_To_UTF16(l_pName, o_pName, i_szName); + return TRUE; + }//Get_Host_Name + + /////////////////////////////////////////////////////////////////////////////// + //Get_Host_Name + static tBOOL Get_Host_Name(tACHAR *o_pName, size_t i_szName) + { + if (0 == gethostname(o_pName, i_szName)) + { + //If the null-terminated hostname is too large to fit, then the name + //is truncated, and no error is returned (but see NOTES below). + //POSIX.1-2001 says that if such truncation occurs, then it is + //unspecified whether the returned buffer includes a terminating + //null byte. + o_pName[i_szName-1] = 0; + } + else + { + strcpy(o_pName, "Unknown:Error"); + } + return TRUE; + }//Get_Host_Name + + /////////////////////////////////////////////////////////////////////////////// + //Get_DateTime + static tBOOL Get_DateTime(tUINT32 &o_rYear, + tUINT32 &o_rMonth, + tUINT32 &o_rDay, + tUINT32 &o_rHour, + tUINT32 &o_rMinute, + tUINT32 &o_rSecond, + tUINT32 &o_rmSec + ) + { + time_t l_sTime = time(NULL); + struct tm l_sTM = *localtime(&l_sTime); + + o_rYear = (uint32_t)(l_sTM.tm_year + 1900); + o_rMonth = (uint32_t)(l_sTM.tm_mon + 1); + o_rDay = (uint32_t)l_sTM.tm_mday; + o_rHour = (uint32_t)l_sTM.tm_hour; + o_rMinute = (uint32_t)l_sTM.tm_min; + o_rSecond = (uint32_t)l_sTM.tm_sec; + o_rmSec = 0; + + return TRUE; + }//Get_Host_Name + +}; + + +#endif //PSYSTEM_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PThreadShell.h b/p7lib/Shared/Platforms/Linux_x86/PThreadShell.h new file mode 100644 index 0000000..d3fea0b --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PThreadShell.h @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PTHREADSHELL_H +#define PTHREADSHELL_H + + +#define THSHELL_CALL_TYPE +#define THSHELL_RET_TYPE void* + +#define THSHELL_RET_OK NULL +#define THSHELL_RET_NOK 0xDEAD + +#include + +//////////////////////////////////////////////////////////////////////////////// +class CThShell +{ +public: + //////////////////////////////////////////////////////////////////////////// + //Base types + typedef pthread_t tTHREAD; + typedef THSHELL_RET_TYPE (THSHELL_CALL_TYPE *tpThreadProc)(void *i_pParameter); + + + //////////////////////////////////////////////////////////////////////////// + //Create + static tBOOL Create(tpThreadProc i_pThread_Proc, + void *i_pPrm, + tTHREAD *o_pThread, + const tXCHAR *i_pName + ) + { + UNUSED_ARG(i_pName); + if ( ( NULL == i_pThread_Proc ) + || ( NULL == o_pThread ) + ) + { + return FALSE; + } + + *o_pThread = 0; + + pthread_attr_t l_sAttr; + int l_iResult = -1; + + pthread_attr_init(&l_sAttr); + pthread_attr_setdetachstate(&l_sAttr, PTHREAD_CREATE_JOINABLE); + + l_iResult = pthread_create(o_pThread, &l_sAttr, i_pThread_Proc, i_pPrm); + + pthread_attr_destroy(&l_sAttr); + +#ifdef __USE_GNU + //if ( (0 == l_iResult) + // && (i_pName) + // ) + //{ + // pthread_setname_np(pthread_self(), i_pName); + //} +#endif + + return (0 == l_iResult) ? TRUE : FALSE; + }//Create + + //////////////////////////////////////////////////////////////////////////// + //Cleanup + static void Cleanup() + { + }//Thread_Cleanup + + + //////////////////////////////////////////////////////////////////////////// + //Close + static tBOOL Close(tTHREAD i_hThread, tUINT32 i_dwTimeOut) + { + UNUSED_ARG(i_dwTimeOut); + + void *l_pRet = THSHELL_RET_OK; + + tUINT32 l_iResult = pthread_join(i_hThread, &l_pRet); + + return (( 0 == l_iResult ) && (THSHELL_RET_OK == l_pRet)) ? TRUE : FALSE; + }//Close + + //////////////////////////////////////////////////////////////////////////// + //Sleep + static void Sleep(tUINT32 i_dwTimeOut) + { + usleep(1000 * i_dwTimeOut); + }//Sleep + +}; + +#endif //PTHREADSHELL_H diff --git a/p7lib/Shared/Platforms/Linux_x86/PTime.h b/p7lib/Shared/Platforms/Linux_x86/PTime.h new file mode 100644 index 0000000..83735b0 --- /dev/null +++ b/p7lib/Shared/Platforms/Linux_x86/PTime.h @@ -0,0 +1,241 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PTIME_H +#define PTIME_H + +#include +#include + +//time offset from January 1, 1601 to January 1, 1970, resolution 100ns +#define TIME_OFFSET_1601_1970 (116444736000000000ULL) + +#define TIME_HRS_100NS 36000000000ull +#define TIME_MIN_100NS 600000000ull +#define TIME_SEC_100NS 10000000ull +#define TIME_MLSC_100NS 10000ull +#define TIME_MCSC_100NS 10ull + +#define TIME_ZONE_AVALIABLE + +//////////////////////////////////////////////////////////////////////////////// +//GetTickCount +static __attribute__ ((unused)) tUINT32 GetTickCount() +{ + tUINT64 l_qwReturn; //Warn:without initialization ! + //timeval l_sTime; + //gettimeofday(&l_sTime, NULL); + + struct timespec l_sTime = {0, 0}; + clock_gettime(CLOCK_MONOTONIC, &l_sTime); + + l_qwReturn = l_sTime.tv_sec; + l_qwReturn *= 1000; + l_qwReturn += l_sTime.tv_nsec/1000000; + + return (tUINT32)l_qwReturn; +}//GetTickCount + + +//////////////////////////////////////////////////////////////////////////////// +//GetPerformanceCounter +static __attribute__ ((unused)) tUINT64 GetPerformanceCounter() +{ + tUINT64 l_qwReturn = 0; + struct timespec l_sTime = {0, 0}; + + clock_gettime(CLOCK_MONOTONIC, &l_sTime); + + l_qwReturn = (tUINT64)(l_sTime.tv_sec) * 10000000; + l_qwReturn += (tUINT64)(l_sTime.tv_nsec) / 100; + + return l_qwReturn; +}//GetPerformanceCounter + + +//////////////////////////////////////////////////////////////////////////////// +//GetPerformanceFrequency +static __attribute__ ((unused)) tUINT64 GetPerformanceFrequency() +{ + return 10000000; //100 nano second +}//GetPerformanceFrequency + + +//////////////////////////////////////////////////////////////////////////////// +//UnpackLocalTime +//convert a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC) +//to readable form +static __attribute__ ((unused)) void UnpackLocalTime(tUINT64 i_qwTime, + tUINT32 &o_rYear, + tUINT32 &o_rMonth, + tUINT32 &o_rDay, + tUINT32 &o_rHour, + tUINT32 &o_rMinutes, + tUINT32 &o_rSeconds, + tUINT32 &o_rMilliseconds, + tUINT32 &o_rMicroseconds, + tUINT32 &o_rNanoseconds + ) +{ + tUINT32 l_dwReminder = i_qwTime % TIME_MLSC_100NS; //micro & 100xNanoseconds + tUINT32 l_dwNano = i_qwTime % 10; + tUINT32 l_dwMicro = l_dwReminder / 10; + + i_qwTime -= l_dwReminder; + + tUINT32 l_dwMilli = (i_qwTime % TIME_SEC_100NS) / TIME_MLSC_100NS; + + i_qwTime -= TIME_OFFSET_1601_1970; + + time_t l_llTime = i_qwTime / TIME_SEC_100NS; + tm *l_pTime = localtime(&l_llTime); + if (l_pTime) + { + o_rYear = 1900 + l_pTime->tm_year; + o_rMonth = 1 + l_pTime->tm_mon; + o_rDay = l_pTime->tm_mday; + o_rHour = l_pTime->tm_hour; + o_rMinutes = l_pTime->tm_min; + o_rSeconds = l_pTime->tm_sec; + o_rMilliseconds = l_dwMilli; + o_rMicroseconds = l_dwMicro; + o_rNanoseconds = l_dwNano; + } + else + { + o_rYear = 0; + o_rMonth = 0; + o_rDay = 0; + o_rHour = 0; + o_rMinutes = 0; + o_rSeconds = 0; + o_rMilliseconds = l_dwMilli; + o_rMicroseconds = l_dwMicro; + o_rNanoseconds = l_dwNano; + } +}//UnpackLocalTime + + +//////////////////////////////////////////////////////////////////////////////// +//PackLocalTime +//convert date & time to 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC) +static __attribute__ ((unused)) tUINT64 PackLocalTime(tUINT32 i_uiYear, + tUINT32 i_uiMonth, + tUINT32 i_uiDay, + tUINT32 i_uiHour, + tUINT32 i_uiMinutes, + tUINT32 i_uiSeconds, + tUINT32 i_uiMilliseconds, + tUINT32 i_uiMicroseconds, + tUINT32 i_uiNanoseconds + ) +{ + tm l_stTime = {0}; + l_stTime.tm_year = (int)i_uiYear - 1900; + l_stTime.tm_mon = (int)i_uiMonth - 1; + l_stTime.tm_mday = (int)i_uiDay; + l_stTime.tm_hour = (int)i_uiHour; + l_stTime.tm_min = (int)i_uiMinutes; + l_stTime.tm_sec = (int)i_uiSeconds; + l_stTime.tm_isdst = -1; + + time_t l_qwTimeT = mktime(&l_stTime); + + tUINT64 l_qwReturn = l_qwTimeT * TIME_SEC_100NS; + l_qwReturn += TIME_OFFSET_1601_1970; + + l_qwReturn += (i_uiMilliseconds * TIME_MLSC_100NS) + (i_uiMicroseconds * 10ull) + (i_uiNanoseconds / 100ull); + + return l_qwReturn; +}//PackLocalTime + + +//////////////////////////////////////////////////////////////////////////////// +//GetSecondOfDay +static inline tUINT32 GetSecondOfDay() +{ + time_t l_llRawtime; + time(&l_llRawtime); + tm *l_pTime = localtime(&l_llRawtime); + + if (l_pTime) + { + return 3600 * (tUINT32)l_pTime->tm_hour + (tUINT32)l_pTime->tm_min * 60 + l_pTime->tm_sec; + } + + return 0; +}//GetSecondOfDay + + +//////////////////////////////////////////////////////////////////////////////// +//GetEpochTime +//return a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC). +static __attribute__ ((unused)) void GetEpochTime(tUINT32 *o_pHi, tUINT32 *o_pLow) +{ + tUINT64 l_qwResult = 0; + struct timeval l_sTime = {0, 0}; + + gettimeofday(&l_sTime, NULL); + + l_qwResult = (tUINT64)(l_sTime.tv_sec) * TIME_SEC_100NS; + l_qwResult += (tUINT64)(l_sTime.tv_usec) * TIME_MCSC_100NS; + l_qwResult += TIME_OFFSET_1601_1970; + + if (o_pHi) + { + *o_pHi = (tUINT32)(l_qwResult >> 32); + } + + if (o_pLow) + { + *o_pLow = (tUINT32)(l_qwResult & 0xFFFFFFFF); + } +}//GetEpochTime + + +//////////////////////////////////////////////////////////////////////////////// +//GetEpochTime +//return a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC). +static inline tUINT64 GetEpochTime() +{ + tUINT32 dwHighDateTime = 0, dwLowDateTime = 0; + + GetEpochTime(&dwHighDateTime, &dwLowDateTime); + + return (((tUINT64)dwHighDateTime) << 32ull) + (tUINT64)dwLowDateTime; +}//GetEpochTime + + +//////////////////////////////////////////////////////////////////////////////// +//GetUtcOffsetSeconds +//return UTC0 offset in seconds +static inline tINT32 GetUtcOffsetSeconds() +{ +#if defined(TIME_ZONE_AVALIABLE) + time_t l_sTime = time(NULL); + struct tm l_stLocal = {0}; + + tzset(); + localtime_r(&l_sTime, &l_stLocal); + + return l_stLocal.tm_gmtoff; +#else + return 0; +#endif +} +#endif //PTIME_H diff --git a/p7lib/Shared/Platforms/Windows_x86/PAtomic.h b/p7lib/Shared/Platforms/Windows_x86/PAtomic.h new file mode 100644 index 0000000..b2be3ff --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PAtomic.h @@ -0,0 +1,27 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +#define ATOMIC_ADD(io_Val, i_Add) InterlockedExchangeAdd((LONG volatile *)io_Val, i_Add) +#define ATOMIC_SUB(io_Val, i_Sub) InterlockedExchangeAdd((LONG volatile *)io_Val, -((tINT32)i_Sub)) +#define ATOMIC_SET(io_Var, i_Val) InterlockedExchange((LONG volatile *)io_Var, (LONG)i_Val) + +#define ATOMIC_INC(io_Val) InterlockedIncrement((LONG volatile *)io_Val) +#define ATOMIC_DEC(io_Val) InterlockedDecrement((LONG volatile *)io_Val) diff --git a/p7lib/Shared/Platforms/Windows_x86/PCRC32.h b/p7lib/Shared/Platforms/Windows_x86/PCRC32.h new file mode 100644 index 0000000..ce677c3 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PCRC32.h @@ -0,0 +1,118 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +static inline tUINT32 Get_CRC32(tUINT8 *i_pData, size_t i_szCount) +{ + tUINT32 l_dwResult = 0xFFFFFFFF; + + if ( (NULL == i_pData) + || (0 >= i_szCount) + ) + { + return l_dwResult; + } + + +#if defined(GTX64) || defined(__linux__) || !defined(_MSC_VER) + + for (size_t l_szI = 0; l_szI < i_szCount; l_szI ++) + { + l_dwResult = g_pCRC32_Table[(l_dwResult ^ i_pData[l_szI]) & 0xFF ] ^ (l_dwResult >> 8); + } + + //Suppress warning that this is not used + (void)g_ppCRC32_Table; + +#else + + // Register use: + // eax - CRC32 value + // ebx - a lot of things + // ecx - CRC32 value + // edx - address of end of buffer + // esi - address of start of buffer + // edi - CRC32 table + __asm + { + // Save the esi and edi registers + push esi + push edi + + mov ecx, l_dwResult // load dwCrc32 + + mov edi, g_ppCRC32_Table // Load the CRC32 table + + mov esi, i_pData // Load buffer + mov ebx, i_szCount // Load dwBytesRead + lea edx, [esi + ebx] // Calculate the end of the buffer + + crc32loop: + xor eax, eax // Clear the eax register + mov bl, byte ptr [esi] // Load the current source byte + + mov al, cl // Copy crc value into eax + inc esi // Advance the source pointer + + xor al, bl // Create the index into the CRC32 table + shr ecx, 8 + + mov ebx, [edi + eax * 4] // Get the value out of the table + xor ecx, ebx // xor with the current byte + + cmp edx, esi // Have we reached the end of the buffer? + jne crc32loop + + // Restore the edi and esi registers + pop edi + pop esi + + lea eax, l_dwResult // Load the pointer to dwCrc32 + mov [eax], ecx // Write the result + } + +#endif + + return l_dwResult; +} + + +// #if defined(_WIN32) || defined(_WIN64) +// tUINT32 Get_CRC32_SSE4(tUINT8 *i_pData, tUINT32 i_szCount) +// { +// tUINT32 l_dwCount = i_szCount >> 2; //count of DWORDs +// tUINT32 l_dwResult = 0x0; +// +// while (l_dwCount--) +// { +// l_dwResult = _mm_crc32_u32(l_dwResult, *(DWORD*)i_pData); +// i_pData += 4; +// } +// +// l_dwCount = i_szCount & 0x3; //bytes count at the tail +// +// while (l_dwCount--) +// { +// l_dwResult = _mm_crc32_u8(l_dwResult, *i_pData); +// i_pData ++; +// } +// +// return l_dwResult; +// } +// #endif diff --git a/p7lib/Shared/Platforms/Windows_x86/PConsole.h b/p7lib/Shared/Platforms/Windows_x86/PConsole.h new file mode 100644 index 0000000..d1df10e --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PConsole.h @@ -0,0 +1,598 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include +#include "AList.h" +#include "PString.h" +#include "IConsole.h" +#include "RBTree.h" + +#pragma warning( disable : 4482 ) + +//http://invisible-island.net/ncurses/ +//https://github.com/fffaraz/awesome-cpp +//http://www.leonerd.org.uk/code/libtickit/ + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Is_Key_Hit +static tBOOL Is_Key_Hit(void) +{ + return (_kbhit()) ? TRUE : FALSE; +}//Is_Key_Hit + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//Get_Char +static tXCHAR Get_Char() +{ + return _getwch(); +}//Get_Char + + +//////////////////////////////////////////////////////////////////////////////// +struct stKeyMap +{ + tUINT16 wKey; + tUINT16 wValue; + stKeyMap(tUINT16 i_wKey, tUINT16 i_wValue) : wKey(i_wKey), wValue(i_wValue) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +//CDesc_Tree +class CKeysTree: + public CRBTree +{ +public: + //////////////////////////////////////////////////////////////////////////// + //~CKeysTree + virtual ~CKeysTree() + { + Clear(); + }//~CRBTree + +protected: + //////////////////////////////////////////////////////////////////////////// + virtual tBOOL Data_Release(stKeyMap* i_pData) + { + delete i_pData; + return TRUE; //memory used from pool, not necessary to return + }// Data_Release + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(tUINT16 i_pKey, stKeyMap *i_pData) + { + return (i_pKey < i_pData->wKey); + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(tUINT16 i_pKey, stKeyMap *i_pData) + { + return (i_pKey == i_pData->wKey); + } +};//CDesc_Tree + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CConsole + : public IConsole +{ + tUINT16 m_pFg[IConsole::eColorsMax]; + tUINT16 m_pBg[IConsole::eColorsMax]; + size_t m_szText; + tXCHAR *m_pText; + HANDLE m_hStdOut; + HANDLE m_hStdIn; + tXCHAR *m_pEmpty; + size_t m_szEmpty; + CKeysTree m_pKeys; +public: + CConsole() + { + m_szText = 32768; + m_pText = (tXCHAR*)malloc(m_szText * sizeof(tXCHAR)); + + m_szEmpty = 0; + m_pEmpty = NULL; + AllocEmptyString(1024); + + m_pFg[IConsole::eBlack] = 0; + m_pFg[IConsole::eBlue] = FOREGROUND_BLUE; + m_pFg[IConsole::eGreen] = FOREGROUND_GREEN; + m_pFg[IConsole::eCyan] = FOREGROUND_BLUE|FOREGROUND_GREEN; + m_pFg[IConsole::eRed] = FOREGROUND_RED; + m_pFg[IConsole::eMagenta] = FOREGROUND_BLUE|FOREGROUND_RED; + m_pFg[IConsole::eBrown] = FOREGROUND_GREEN|FOREGROUND_RED; + m_pFg[IConsole::eLightGray] = FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED; + m_pFg[IConsole::eDarkGray] = FOREGROUND_INTENSITY; + m_pFg[IConsole::eLightBlue] = FOREGROUND_BLUE|FOREGROUND_INTENSITY; + m_pFg[IConsole::eLightGreen] = FOREGROUND_GREEN|FOREGROUND_INTENSITY; + m_pFg[IConsole::eLightCyan] = FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY; + m_pFg[IConsole::eLightRed] = FOREGROUND_RED|FOREGROUND_INTENSITY; + m_pFg[IConsole::eLightMagenta] = FOREGROUND_BLUE|FOREGROUND_RED|FOREGROUND_INTENSITY; + m_pFg[IConsole::eYellow] = FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY; + m_pFg[IConsole::eWhite] = FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY; + + m_pBg[IConsole::eBlack] = 0; + m_pBg[IConsole::eBlue] = BACKGROUND_BLUE; + m_pBg[IConsole::eGreen] = BACKGROUND_GREEN; + m_pBg[IConsole::eCyan] = BACKGROUND_BLUE|BACKGROUND_GREEN; + m_pBg[IConsole::eRed] = BACKGROUND_RED; + m_pBg[IConsole::eMagenta] = BACKGROUND_BLUE|BACKGROUND_RED; + m_pBg[IConsole::eBrown] = BACKGROUND_GREEN|BACKGROUND_RED; + m_pBg[IConsole::eLightGray] = BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED; + m_pBg[IConsole::eDarkGray] = BACKGROUND_INTENSITY; + m_pBg[IConsole::eLightBlue] = BACKGROUND_BLUE|BACKGROUND_INTENSITY; + m_pBg[IConsole::eLightGreen] = BACKGROUND_GREEN|BACKGROUND_INTENSITY; + m_pBg[IConsole::eLightCyan] = BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_INTENSITY; + m_pBg[IConsole::eLightRed] = BACKGROUND_RED|BACKGROUND_INTENSITY; + m_pBg[IConsole::eLightMagenta] = BACKGROUND_BLUE|BACKGROUND_RED|BACKGROUND_INTENSITY; + m_pBg[IConsole::eYellow] = BACKGROUND_GREEN|BACKGROUND_RED|BACKGROUND_INTENSITY; + m_pBg[IConsole::eWhite] = BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED|BACKGROUND_INTENSITY; + + m_hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + m_hStdIn = GetStdHandle(STD_INPUT_HANDLE); + SetConsoleMode(m_hStdIn, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT); + + m_pKeys.Push(new stKeyMap(38, IConsole::eKeyArrowUp), 38); + m_pKeys.Push(new stKeyMap(40, IConsole::eKeyArrowDown), 40); + m_pKeys.Push(new stKeyMap(37, IConsole::eKeyArrowLeft), 37); + m_pKeys.Push(new stKeyMap(39, IConsole::eKeyArrowRight), 39); + m_pKeys.Push(new stKeyMap(35, IConsole::eKeyEnd), 35); + m_pKeys.Push(new stKeyMap(36, IConsole::eKeyHome), 36); + m_pKeys.Push(new stKeyMap(33, IConsole::eKeyPageUp), 33); + m_pKeys.Push(new stKeyMap(34, IConsole::eKeyPageDown), 34); + + m_pKeys.Push(new stKeyMap(112, IConsole::eKeyF1), 112); + m_pKeys.Push(new stKeyMap(113, IConsole::eKeyF2), 113); + m_pKeys.Push(new stKeyMap(114, IConsole::eKeyF3), 114); + m_pKeys.Push(new stKeyMap(115, IConsole::eKeyF4), 115); + m_pKeys.Push(new stKeyMap(116, IConsole::eKeyF5), 116); + m_pKeys.Push(new stKeyMap(117, IConsole::eKeyF6), 117); + m_pKeys.Push(new stKeyMap(118, IConsole::eKeyF7), 118); + m_pKeys.Push(new stKeyMap(119, IConsole::eKeyF8), 119); + m_pKeys.Push(new stKeyMap(120, IConsole::eKeyF9), 120); + m_pKeys.Push(new stKeyMap(121, IConsole::eKeyF10), 121); + m_pKeys.Push(new stKeyMap(122, IConsole::eKeyF11), 122); + m_pKeys.Push(new stKeyMap(123, IConsole::eKeyF12), 123); + m_pKeys.Push(new stKeyMap(45, IConsole::eKeyInsert), 45); + m_pKeys.Push(new stKeyMap(46, IConsole::eKeyDel), 46); + m_pKeys.Push(new stKeyMap(9, IConsole::eKeyTab), 9); + m_pKeys.Push(new stKeyMap(8, IConsole::eKeyBackSpace), 8); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~CConsole() + { + if (m_pText) + { + free(m_pText); + m_pText = NULL; + } + + if (m_pEmpty) + { + free(m_pEmpty); + m_pEmpty = NULL; + } + + m_pKeys.Clear(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL SetCursor(tUINT32 i_uX, tUINT32 i_uY) + { + COORD l_cCoord = {(SHORT)i_uX, (SHORT)i_uY}; + return SetConsoleCursorPosition(m_hStdOut, l_cCoord); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetCursorX() + { + CONSOLE_SCREEN_BUFFER_INFO l_sCsbi = {0}; + if (GetConsoleScreenBufferInfo(m_hStdOut, &l_sCsbi)) + { + return l_sCsbi.dwCursorPosition.X; + } + + return 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL GetInput(IConsole::sInput &o_rInput) + { + INPUT_RECORD l_stRecord = {}; + DWORD l_dwRead = 0; + + GetNumberOfConsoleInputEvents(m_hStdIn, &l_dwRead); + + if (!l_dwRead) + { + return FALSE; + } + + ReadConsoleInput(m_hStdIn, &l_stRecord, 1, &l_dwRead); + + if (!l_dwRead) + { + return FALSE; + } + + if (FOCUS_EVENT == l_stRecord.EventType) + { + o_rInput.eEvent = IConsole::eEvent::eFocus; + o_rInput.stFocus.bFocus = l_stRecord.Event.FocusEvent.bSetFocus; + } + else if (KEY_EVENT == l_stRecord.EventType) + { + o_rInput.eEvent = IConsole::eEvent::eKey; + o_rInput.stKey.bDown = l_stRecord.Event.KeyEvent.bKeyDown; + o_rInput.stKey.uControls = l_stRecord.Event.KeyEvent.dwControlKeyState; + o_rInput.stKey.wCount = l_stRecord.Event.KeyEvent.wRepeatCount; + + stKeyMap *l_pKey = m_pKeys.Find(l_stRecord.Event.KeyEvent.wVirtualKeyCode); + if (l_pKey) + { + o_rInput.stKey.wKey = l_pKey->wValue; + } + else + { + o_rInput.stKey.wKey = l_stRecord.Event.KeyEvent.wVirtualKeyCode; + } + } + else if (MOUSE_EVENT == l_stRecord.EventType) + { + o_rInput.eEvent = IConsole::eEvent::eMouse; + o_rInput.stMouse.uButton = l_stRecord.Event.MouseEvent.dwButtonState; + o_rInput.stMouse.uX = l_stRecord.Event.MouseEvent.dwMousePosition.X; + o_rInput.stMouse.uY = l_stRecord.Event.MouseEvent.dwMousePosition.Y; + } + else if (WINDOW_BUFFER_SIZE_EVENT == l_stRecord.EventType) + { + o_rInput.eEvent = IConsole::eEvent::eSize; + o_rInput.stSize.uW = l_stRecord.Event.WindowBufferSizeEvent.dwSize.X; + o_rInput.stSize.uH = l_stRecord.Event.WindowBufferSizeEvent.dwSize.Y; + } + else + { + return FALSE; + } + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetCursorY() + { + CONSOLE_SCREEN_BUFFER_INFO l_sCsbi = {0}; + if (GetConsoleScreenBufferInfo(m_hStdOut, &l_sCsbi)) + { + return l_sCsbi.dwCursorPosition.Y; + } + + return 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetWidth() + { + CONSOLE_SCREEN_BUFFER_INFO l_sCsbi = {0}; + if (GetConsoleScreenBufferInfo(m_hStdOut, &l_sCsbi)) + { + return l_sCsbi.srWindow.Right - l_sCsbi.srWindow.Left + 1; + } + return 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tUINT32 GetHeight() + { + CONSOLE_SCREEN_BUFFER_INFO l_sCsbi = {0}; + if (GetConsoleScreenBufferInfo(m_hStdOut, &l_sCsbi)) + { + return l_sCsbi.srWindow.Bottom - l_sCsbi.srWindow.Top + 1; + } + return 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL SetTextAttr(IConsole::eColor i_eFg, IConsole::eColor i_eBg) + { + if ( (i_eFg < 0) + || (i_eFg >= IConsole::eColorsMax) + || (i_eBg < 0) + || (i_eBg >= IConsole::eColorsMax) + ) + { + return FALSE; + } + + return SetConsoleTextAttribute(m_hStdOut, m_pFg[i_eFg] | m_pBg[i_eBg]); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Clear() + { + COORD l_sCoordScreen = { 0, 0 }; // home for the cursor + DWORD l_dwCharsWritten = 0; + DWORD l_dwConSize = 0; + CONSOLE_SCREEN_BUFFER_INFO l_sCsbi = {0}; + + // Get the number of character cells in the current buffer. + if( !GetConsoleScreenBufferInfo( m_hStdOut, &l_sCsbi )) + { + return FALSE; + } + + l_dwConSize = l_sCsbi.dwSize.X * l_sCsbi.dwSize.Y; + + // Fill the entire screen with blanks. + if( !FillConsoleOutputCharacterW( m_hStdOut, // Handle to console screen buffer + L' ', // Character to write to the buffer + l_dwConSize, // Number of cells to write + l_sCoordScreen, // Coordinates of first cell + &l_dwCharsWritten )) // Receive number of characters written + { + return FALSE; + } + + // Get the current text attribute. + if( !GetConsoleScreenBufferInfo( m_hStdOut, &l_sCsbi )) + { + return FALSE; + } + + // Set the buffer's attributes accordingly. + if( !FillConsoleOutputAttribute( m_hStdOut, // Handle to console screen buffer + l_sCsbi.wAttributes, // Character attributes to use + l_dwConSize, // Number of cells to set attribute + l_sCoordScreen, // Coordinates of first cell + &l_dwCharsWritten )) // Receive number of characters written + { + return FALSE; + } + + // Put the cursor at its home coordinates. + return SetConsoleCursorPosition( m_hStdOut, l_sCoordScreen ); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Clear(tUINT32 i_uX, tUINT32 i_uY, tUINT32 i_uW, tUINT32 i_uH, IConsole::eColor i_eBg) + { + tUINT32 l_uiW = GetWidth(); + tUINT32 l_uiH = GetHeight(); + + if ( (i_uX > l_uiW) + || (i_uY > l_uiH) + || (!i_uW) + || (!i_uH) + ) + { + return FALSE; + } + + if ((i_uX + i_uW) > l_uiW) + { + i_uW = l_uiW - i_uX; + } + + if ((i_uY + i_uH) > l_uiH) + { + i_uH = l_uiH - i_uY; + } + + if (i_uW > m_szEmpty) + { + if (!AllocEmptyString((size_t)i_uW)) + { + return FALSE; + } + } + + if (!SetTextAttr(IConsole::eBlack, i_eBg)) + { + return FALSE; + } + + tUINT32 l_uiX = GetCursorX(); + tUINT32 l_uiY = GetCursorY(); + tUINT32 l_uiYOld = l_uiY; + while (i_uH--) + { + SetCursor(i_uX, i_uY++); + WriteTextB(m_pEmpty, i_uW); + } + + SetCursor(l_uiX, l_uiYOld); + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t WriteTextB(const tXCHAR *i_pText, size_t i_szText) + { + DWORD l_dwWritten = 0; + return WriteConsole(m_hStdOut, i_pText, (DWORD)i_szText, &l_dwWritten, NULL); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t WriteTextB(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + tXCHAR *i_pText, + size_t i_szText, + size_t i_szTextMax + ) + { + if ( (i_szLenMin > i_szLenMax) + || (!i_pText) + || (8 >= i_szTextMax) + || (i_szText >= i_szTextMax) + ) + { + return 0; + } + + if (!SetTextAttr(i_eFg, i_eBg)) + { + return 0; + } + + tXCHAR *l_pText = i_pText; + + if (!i_szText) + { + i_szText = PStrLen(i_pText); + } + + //if there is offset, recalculate all inputs + if (i_szOffset) + { + if (i_szOffset < i_szText) //set sext offset and recalculate all + { + l_pText = l_pText + i_szOffset; + i_szText -= i_szOffset; + i_szTextMax -= i_szOffset; + i_szOffset = 0; + *l_pText = TM('<'); + } + else //if (i_szOffset >= i_szText) + { + l_pText = m_pText; + *l_pText = TM('<'); + i_szText = 1; + i_szTextMax= m_szText; + } + } + + + if (i_szText > i_szLenMax) + { + i_szText = i_szLenMax; + l_pText[i_szText-1] = TM('>'); + } + else if (i_szText < i_szLenMin) + { + if (i_szTextMax < (i_szLenMin + 1)) + { + PStrNCpy(m_pText, m_szText, l_pText, i_szText); + l_pText = m_pText; + i_szTextMax = m_szText; + } + + tXCHAR *l_pIter = l_pText + i_szText; + + while (i_szText < i_szLenMin) + { + *l_pIter = TM(' '); + l_pIter ++; + i_szText++; + } + } + + if (i_szText < i_szTextMax) + { + l_pText[i_szText] = 0; + } + else + { + l_pText[i_szText-1] = 0; + } + + DWORD l_dwWritten = 0; + if (!WriteConsole(m_hStdOut, l_pText, (DWORD)i_szText, &l_dwWritten, NULL)) + { + return 0; + } + + return (size_t)l_dwWritten; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + size_t WriteTextF(IConsole::eColor i_eFg, + IConsole::eColor i_eBg, + size_t i_szLenMin, + size_t i_szLenMax, + size_t i_szOffset, + const tXCHAR *i_pFormat, + va_list i_pVA + ) + { + int l_iReturn = PVsnprintf(m_pText, m_szText, i_pFormat, i_pVA); + + if (0 > l_iReturn) + { + return 0; + } + + return WriteTextB(i_eFg, i_eBg, i_szLenMin, i_szLenMax, i_szOffset, m_pText, (size_t)l_iReturn, m_szText); + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Present() + { + return TRUE; + } + +protected: + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL AllocEmptyString(size_t i_szEmpty) + { + if (m_pEmpty) + { + free(m_pEmpty); + } + + if (i_szEmpty > 4096) + { + i_szEmpty = 4096; + } + + m_szEmpty = i_szEmpty; + m_pEmpty = (tXCHAR*)malloc(m_szEmpty * sizeof(tXCHAR)); + + if (!m_pEmpty) + { + return FALSE; + } + + tXCHAR *l_pEmpty = m_pEmpty; + size_t l_szIterator = m_szEmpty; + + while (l_szIterator--) + { + *l_pEmpty = TM(' '); + l_pEmpty++; + } + + return TRUE; + } +}; diff --git a/p7lib/Shared/Platforms/Windows_x86/PDnsTxtResolver.h b/p7lib/Shared/Platforms/Windows_x86/PDnsTxtResolver.h new file mode 100644 index 0000000..d90940a --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PDnsTxtResolver.h @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#include +#include + +#include "GTypes.h" +#include "AList.h" + +class CDnsTxt: public CAList +{ +protected: + virtual tBOOL Data_Release(tACHAR *i_pStr) + { + if (NULL == i_pStr) + { + return FALSE; + } + + free(i_pStr); + return TRUE; + }//CListBase::Data_Release +}; + + +tBOOL static inline GetDnsTxtRecords(const tACHAR *i_pDomain, CDnsTxt &io_rList) +{ + DNS_RECORDA *l_pRecord = NULL; + DNS_RECORDA *l_pIter = NULL; + DNS_STATUS l_lStatus = 0; + tACHAR *l_pReturn = NULL; + + io_rList.Clear(TRUE); + + l_lStatus = DnsQuery_A(i_pDomain, + DNS_TYPE_TEXT, + DNS_QUERY_STANDARD + | DNS_QUERY_WIRE_ONLY + | DNS_QUERY_NO_LOCAL_NAME + | DNS_QUERY_BYPASS_CACHE + //| DNS_QUERY_USE_TCP_ONLY + | DNS_QUERY_NO_HOSTS_FILE, + NULL, + (DNS_RECORD**)&l_pRecord, + NULL + ); + if ( (0 == l_lStatus) + && (l_pRecord) + ) + { + l_pIter = l_pRecord; + while (l_pIter) + { + if (DNS_TYPE_TEXT == l_pIter->wType) + { + if (l_pIter->Data.Txt.dwStringCount) + { + for (DWORD l_dwI = 0; l_dwI < l_pIter->Data.Txt.dwStringCount; l_dwI++) + { + if (l_pIter->Data.Txt.pStringArray[l_dwI]) + { + io_rList.Push_Last(strdup(l_pIter->Data.Txt.pStringArray[l_dwI])); + } + } + } + } + + if (!l_pReturn) + { + l_pIter = l_pIter->pNext; + } + else + { + l_pIter = NULL; + } + } + + DnsRecordListFree(l_pRecord, DnsFreeRecordList); + } + + return (io_rList.Count() != 0); +} diff --git a/p7lib/Shared/Platforms/Windows_x86/PFile.h b/p7lib/Shared/Platforms/Windows_x86/PFile.h new file mode 100644 index 0000000..30e81c7 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PFile.h @@ -0,0 +1,331 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PFILE_H +#define PFILE_H + + +//UTF-8 text file header - {0xEF, 0xBB, 0xBF} + +//////////////////////////////////////////////////////////////////////////////// +class CPFile + : public IFile //virtual +{ + volatile tINT32 m_iRCnt; + HANDLE m_hFile; +public: + //////////////////////////////////////////////////////////////////////////// + CPFile() + : m_iRCnt(1) + , m_hFile(NULL) + { + } + + //////////////////////////////////////////////////////////////////////////// + virtual ~CPFile() + { + Close(FALSE); + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL IsOpened() + { + return (NULL != m_hFile); + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Open(const tXCHAR *i_pName, tUINT32 i_dwFlags) + { + DWORD l_dwAccess = GENERIC_READ; + DWORD l_dwShare = 0; + + if (EACCESS_WRITE & i_dwFlags) + { + l_dwAccess |= GENERIC_WRITE; + } + + if (ESHARE_READ & i_dwFlags) + { + l_dwShare |= FILE_SHARE_READ; + } + + if (ESHARE_WRITE & i_dwFlags) + { + l_dwShare |= FILE_SHARE_WRITE; + } + + Close(TRUE); + + m_hFile = CreateFileW(i_pName, + l_dwAccess, + l_dwShare, + NULL, + (i_dwFlags & EOPEN) ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if ( (NULL == m_hFile) + || (INVALID_HANDLE_VALUE == m_hFile) + ) + { + m_hFile = NULL; + } + + return (NULL != m_hFile); + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Close(tBOOL i_bFlush) + { + tBOOL l_bReturn = TRUE; + HANDLE l_hTemp = NULL; + + if (NULL == m_hFile) + { + return TRUE; + } + + if (i_bFlush) + { + if (FALSE == FlushFileBuffers(m_hFile)) + { + l_bReturn = FALSE; + goto l_lExit; + } + } + + l_hTemp = m_hFile; + m_hFile = NULL; + + if (FALSE == CloseHandle(l_hTemp)) + { + l_bReturn = FALSE; + goto l_lExit; + } + + l_lExit: + return l_bReturn; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Set_Position(tUINT64 i_qwOffset) + { + if (NULL == m_hFile) + { + return FALSE; + } + + LONG l_lOffsetHi = (LONG)(i_qwOffset >> 32); + + if ( (INVALID_SET_FILE_POINTER == SetFilePointer(m_hFile, + (LONG)i_qwOffset, + &l_lOffsetHi, + FILE_BEGIN + ) + + ) + && (NO_ERROR != GetLastError()) + ) + { + return FALSE; + } + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////// + tUINT64 Get_Position() + { + if (INVALID_HANDLE_VALUE == m_hFile) + { + return 0ULL; + } + + if (NULL == m_hFile) + { + return FALSE; + } + + LONG l_lOffsetHi = 0; + DWORD l_dwOffsetLow = SetFilePointer(m_hFile, + 0, + &l_lOffsetHi, + FILE_CURRENT + ); + + if ( (INVALID_SET_FILE_POINTER != l_dwOffsetLow) + || (NO_ERROR == GetLastError()) + ) + { + return (((tUINT64)l_lOffsetHi) << 32) + (tUINT64)l_dwOffsetLow; + } + + return 0ULL; + } + + //////////////////////////////////////////////////////////////////////////// + tUINT64 Get_Size() + { + if (INVALID_HANDLE_VALUE == m_hFile) + { + return 0ULL; + } + + LARGE_INTEGER l_qwSize; + + if (FALSE == GetFileSizeEx(m_hFile, &l_qwSize)) + { + l_qwSize.QuadPart = 0LL; + } + + return (tUINT64)l_qwSize.QuadPart; + } + + //////////////////////////////////////////////////////////////////////////// + size_t Write(const tUINT8 *i_pBuffer, size_t i_szBuffer, tBOOL i_bFlush) + { + if ( (INVALID_HANDLE_VALUE == m_hFile) + || (NULL == i_pBuffer) + || (0 == i_szBuffer) + ) + { + return 0ULL; + } + + size_t l_szReturn = 0; + DWORD l_dwWritten = 0; + + while (l_szReturn < i_szBuffer) + { + l_dwWritten = 0; + if (!WriteFile(m_hFile, + i_pBuffer + l_szReturn, + (DWORD)(i_szBuffer - l_szReturn), + &l_dwWritten, + NULL + ) + ) + { + l_szReturn += (size_t)l_dwWritten; + break; + } + else + { + l_szReturn += (size_t)l_dwWritten; + } + } + + if ( (i_bFlush) + && (l_szReturn) + ) + { + FlushFileBuffers(m_hFile); + } + + return l_szReturn; + } + + //////////////////////////////////////////////////////////////////////////// + size_t Read(tUINT8 *o_pBuffer, size_t i_szBuffer) + { + if ( (INVALID_HANDLE_VALUE == m_hFile) + || (NULL == o_pBuffer) + || (0 == i_szBuffer) + ) + { + return 0ULL; + } + + size_t l_szReturn = 0; + DWORD l_dwRead = 0; + + while (l_szReturn < i_szBuffer) + { + l_dwRead = 0; + if (ReadFile(m_hFile, + o_pBuffer + l_szReturn, + (DWORD)(i_szBuffer - l_szReturn), + &l_dwRead, + NULL + ) + ) + { + l_szReturn += (size_t)l_dwRead; + } + else + { + l_szReturn += (size_t)l_dwRead; + break; + } + + if (0 >= l_dwRead) + { + break; + } + } + + return l_szReturn; + } + + + //////////////////////////////////////////////////////////////////////////// + tINT32 Add_Ref() + { + return ATOMIC_INC(&m_iRCnt); + } + + + //////////////////////////////////////////////////////////////////////////// + tINT32 Release() + { + volatile tINT32 l_iReturn = ATOMIC_DEC(&m_iRCnt); + + if (0 >= l_iReturn) + { + delete this; + } + + return l_iReturn; + } +}; + +#endif //PFILE_H + + + +/* + CPFile l_cFile; + const tUINT8 l_pHeader[] = {0xEF, 0xBB, 0xBF}; + const char l_pText[] = "Some Text For me !\xD\xA Another Text\xD\xA Third Text"; + tUINT64 l_qwCount = 0; + tUINT8 l_pBuffer[256] = {0}; + + l_cFile.Open("./ABC.txt", IFile::ECREATE | IFile::ESHARE_WRITE); + + l_qwCount = l_cFile.Write(l_pHeader, LENGTH(l_pHeader), FALSE); + l_qwCount = l_cFile.Write((tUINT8*)l_pText, LENGTH(l_pText) - 1, TRUE); + + l_qwCount = l_cFile.Get_Size(); + + l_cFile.Set_Position(0); + + l_qwCount = l_cFile.Read(l_pBuffer, LENGTH(l_pBuffer)); + + l_cFile.Close(TRUE); +*/ diff --git a/p7lib/Shared/Platforms/Windows_x86/PFileSystem.h b/p7lib/Shared/Platforms/Windows_x86/PFileSystem.h new file mode 100644 index 0000000..abba701 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PFileSystem.h @@ -0,0 +1,618 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#pragma warning(disable : 4091) + +#include "Shlobj.h" + +class CFSYS +{ +public: + //////////////////////////////////////////////////////////////////////////// + //Directory_Exists + static BOOL Directory_Exists(const wchar_t * i_pPath) + { + DWORD l_dwFile_Attr = 0; + BOOL l_bRes = FALSE; + + if (NULL == i_pPath) + { + return l_bRes; + } + + l_dwFile_Attr = GetFileAttributesW(i_pPath); + //check if that directory is exist ... + if ((FILE_ATTRIBUTE_DIRECTORY & l_dwFile_Attr) && + ( ((DWORD)-1) != l_dwFile_Attr) + ) + { + l_bRes = TRUE; + } + + return l_bRes; + }//Directory_Exists + + + //////////////////////////////////////////////////////////////////////////// + //Directory_Create + static BOOL Directory_Create(const wchar_t *i_pDirectory) + { + if (NULL == i_pDirectory) + { + return FALSE; + } + + wchar_t *l_pDirectory = _wcsdup(i_pDirectory); + tBOOL l_bReturn = FALSE; + + if (NULL == l_pDirectory) + { + return FALSE; + } + + size_t l_szLength = wcslen(l_pDirectory); + + for (size_t l_dwI = 3; /*wcslen(L"C:\\")*/ l_dwI < l_szLength; l_dwI++) + { + if ( (L'\\' == l_pDirectory[l_dwI]) + || (L'/' == l_pDirectory[l_dwI]) + ) + { + l_pDirectory[l_dwI] = 0; + if (FALSE == Directory_Exists(l_pDirectory)) + { + CreateDirectoryW(l_pDirectory, NULL); + } + + l_pDirectory[l_dwI] = L'\\'; + } + } + + CreateDirectoryW(l_pDirectory, NULL); + l_bReturn = Directory_Exists(l_pDirectory); + + free(l_pDirectory); + l_pDirectory = NULL; + + return l_bReturn; + }//Directory_Create + + //////////////////////////////////////////////////////////////////////////// + //Directory_Delete + static BOOL Directory_Delete(const wchar_t *i_pDirectory) + { + if (NULL == i_pDirectory) + { + return FALSE; + } + + return RemoveDirectoryW(i_pDirectory); + } + + //////////////////////////////////////////////////////////////////////////// + //File_Exists + static BOOL File_Exists(const wchar_t * i_pFileName) + { + HANDLE l_hFind_Handle = NULL; + WIN32_FIND_DATAW l_tFind_Data; + BOOL l_bRes = FALSE; + + if (NULL == i_pFileName) + { + return l_bRes; + } + + memset(&l_tFind_Data, 0, sizeof(WIN32_FIND_DATAW)); + + l_hFind_Handle = FindFirstFileW(i_pFileName, &l_tFind_Data); + if (INVALID_HANDLE_VALUE != l_hFind_Handle) + { + l_bRes = (0 == (l_tFind_Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)); + FindClose(l_hFind_Handle); + l_hFind_Handle = NULL; + } + + return l_bRes; + }//File_Exists + + + //////////////////////////////////////////////////////////////////////////// + // Enumerate_Files + static void Enumerate_Files(CBList *io_pFilesList, + CWString *i_pDirectory, + const wchar_t *i_pMask, //for example L"*.dll" + DWORD i_dwDepth = 0xFFFFFF + ) + { + WIN32_FIND_DATAW l_sFind_Info = {0}; + HANDLE l_hFind = INVALID_HANDLE_VALUE; + DWORD l_dwLength = i_pDirectory->Length(); + CWString l_cSearch_Path; + + + //************************************************************************** + // Enumerate all files in current directory + l_cSearch_Path.Set(i_pDirectory->Get()); + l_cSearch_Path.Append(2, L"\\", i_pMask); + + l_hFind = FindFirstFileW(l_cSearch_Path.Get(), &l_sFind_Info); + + while(INVALID_HANDLE_VALUE != l_hFind) + { + if (0 == (l_sFind_Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + CWString *l_pFile = new CWString(); + if (l_pFile) + { + l_pFile->Set(i_pDirectory->Get()); + l_pFile->Append(2, L"\\", l_sFind_Info.cFileName); + io_pFilesList->Add_After(io_pFilesList->Get_Last(), l_pFile); + } + } + + if (! FindNextFileW(l_hFind, &l_sFind_Info)) + { + FindClose(l_hFind); + l_hFind = INVALID_HANDLE_VALUE; + } + } //while(INVALID_HANDLE_VALUE != hFind) + + + //************************************************************************** + // Enumerate all sub directories in current directory .... + if (i_dwDepth) + { + l_cSearch_Path.Set(i_pDirectory->Get()); + l_cSearch_Path.Append(1, L"\\*"); + + l_hFind = FindFirstFileW(l_cSearch_Path.Get(), &l_sFind_Info); + + while(INVALID_HANDLE_VALUE != l_hFind) + { + if ( (0 != (l_sFind_Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + && (0 != wcscmp(l_sFind_Info.cFileName, L".")) + && (0 != wcscmp(l_sFind_Info.cFileName, L"..")) + ) + { + i_pDirectory->Append(2, L"\\", l_sFind_Info.cFileName); + Enumerate_Files(io_pFilesList, i_pDirectory, i_pMask, i_dwDepth - 1); + i_pDirectory->Trim(l_dwLength); + } + + if (! FindNextFileW(l_hFind, &l_sFind_Info)) + { + FindClose(l_hFind); + l_hFind = INVALID_HANDLE_VALUE; + } + } //while(INVALID_HANDLE_VALUE != hFind) + } + }// Enumerate_Files + + + //////////////////////////////////////////////////////////////////////////// + // Enumerate_Dirs + static void Enumerate_Dirs(CBList *io_pFilesList, const tXCHAR *i_pRoot) + { + WIN32_FIND_DATAW l_sFind_Info = {0}; + HANDLE l_hFind = INVALID_HANDLE_VALUE; + + if (!io_pFilesList) + { + return; + } + + if ( (i_pRoot) + && (*i_pRoot) + ) + { + CWString l_cSearch_Path; + + + //************************************************************************** + // Enumerate all files in current directory + l_cSearch_Path.Set(i_pRoot); + l_cSearch_Path.Append(1, L"\\*"); + + l_hFind = FindFirstFileW(l_cSearch_Path.Get(), &l_sFind_Info); + + while(INVALID_HANDLE_VALUE != l_hFind) + { + if ( (0 != (l_sFind_Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + && (0 != wcscmp(l_sFind_Info.cFileName, L".")) + && (0 != wcscmp(l_sFind_Info.cFileName, L"..")) + ) + { + CWString *l_pFile = new CWString(); + if (l_pFile) + { + l_pFile->Set(i_pRoot); + l_pFile->Append(2, L"\\", l_sFind_Info.cFileName); + io_pFilesList->Add_After(io_pFilesList->Get_Last(), l_pFile); + } + } + + if (! FindNextFileW(l_hFind, &l_sFind_Info)) + { + FindClose(l_hFind); + l_hFind = INVALID_HANDLE_VALUE; + } + } //while(INVALID_HANDLE_VALUE != hFind) + } + else + { + DWORD l_dwDrives = GetLogicalDrives(); + DWORD l_dwBit = 0; + tXCHAR l_pDrive[4]; + + l_pDrive[0] = TM('A'); + l_pDrive[1] = TM(':'); + l_pDrive[2] = TM('\\'); + l_pDrive[3] = 0; + + while (l_dwDrives) + { + if (l_dwDrives & 1) + { + l_pDrive[0] = (tXCHAR)(l_dwBit + TM('A')); + + UINT l_uiType = GetDriveTypeW(l_pDrive); + if ( (DRIVE_UNKNOWN != l_uiType) + && (DRIVE_NO_ROOT_DIR != l_uiType) + ) + { + CWString *l_pFile = new CWString(); + if (l_pFile) + { + l_pFile->Set(l_pDrive); + io_pFilesList->Add_After(io_pFilesList->Get_Last(), l_pFile); + } + } + } + + l_dwDrives = l_dwDrives >> 1; + l_dwBit ++; + } + } + }// Enumerate_Dirs + + + //////////////////////////////////////////////////////////////////////////// + //Get_Version + static UINT64 Get_Version(const wchar_t *i_pFile) + { + DWORD l_dwUnknown = 0; + DWORD l_dwFileInfoSize = 0; + UINT64 l_qwReturn = 0; + CWString l_cPath; + + if (!i_pFile) + { + l_cPath.Realloc(4096); + if (GetModuleFileNameW(GetModuleHandleW(NULL), + l_cPath.Get(), + l_cPath.Max_Length() + ) + ) + { + i_pFile = l_cPath.Get(); + } + else + { + return 0ull; + } + } + + l_dwFileInfoSize = GetFileVersionInfoSizeW(i_pFile, &l_dwUnknown); + + if (l_dwFileInfoSize) + { + BYTE * l_pFileInfo = new BYTE[l_dwFileInfoSize]; + if (l_pFileInfo) + { + memset(l_pFileInfo, 0, l_dwFileInfoSize); + + if (GetFileVersionInfoW(i_pFile, 0, l_dwFileInfoSize, l_pFileInfo) ) + { + VS_FIXEDFILEINFO * l_tVersion = NULL; + UINT l_dwSize = 0; + if (VerQueryValueW(l_pFileInfo, L"\\", (LPVOID *)&l_tVersion, &l_dwSize)) + { + l_qwReturn = (((UINT64)l_tVersion->dwProductVersionMS) << 32) + + l_tVersion->dwProductVersionLS; + } + } + + if (l_pFileInfo) + { + delete [ ] l_pFileInfo; + l_pFileInfo = NULL; + } + } //if (l_pFileInfo) + } //if (l_dwFileInfoSize) + + return l_qwReturn; + }//Get_Version + + + //////////////////////////////////////////////////////////////////////////// + //Get_TextResource + static tBOOL Get_TextResource(const tXCHAR *i_pFile, + const tXCHAR *i_pName, + tXCHAR *o_pBuffer, + size_t i_szBuffer + ) + { + tBOOL l_bReturn = FALSE; + tUINT32 l_dwUnknown = 0; + DWORD l_dwFileInfoSize = 0; + tUINT32 *l_pCodePage = NULL; + tUINT8 *l_pFileInfo = NULL; + tUINT32 l_dwSize = 0; + wchar_t *l_pValue = NULL; + const size_t l_szName = 256; + wchar_t l_pName[l_szName]; + + CWString l_cPath; + + if ( (!i_pName) + || (!o_pBuffer) + || (32 > i_szBuffer) + || ((l_szName / 2) < wcslen(i_pName)) + ) + { + goto l_lblExit; + } + + if (!i_pFile) + { + l_cPath.Realloc(4096); + if (GetModuleFileNameW(GetModuleHandleW(NULL), + l_cPath.Get(), + l_cPath.Max_Length() + ) + ) + { + i_pFile = l_cPath.Get(); + } + else + { + goto l_lblExit; + } + } + + l_dwFileInfoSize = GetFileVersionInfoSizeW(i_pFile, (LPDWORD)&l_dwUnknown); + + if (!l_dwFileInfoSize) + { + goto l_lblExit; + } + + l_pFileInfo = (tUINT8*)malloc(l_dwFileInfoSize); + + if (!l_pFileInfo) + { + goto l_lblExit; + } + + memset(l_pFileInfo, 0, l_dwFileInfoSize); + + if (!GetFileVersionInfoW(i_pFile, 0, l_dwFileInfoSize, l_pFileInfo) ) + { + goto l_lblExit; + } + + if (!VerQueryValueW(l_pFileInfo, L"\\VarFileInfo\\Translation", (LPVOID*) &l_pCodePage, &l_dwSize)) + { + goto l_lblExit; + } + + swprintf_s(l_pName, l_szName, + L"\\StringFileInfo\\%08x\\%s", + (tUINT32)((*l_pCodePage) << 16 | (*l_pCodePage) >> 16), + i_pName + ); + + if (!VerQueryValueW(l_pFileInfo, l_pName, (LPVOID *)&l_pValue, &l_dwSize)) + { + goto l_lblExit; + } + + + wcsncpy_s(o_pBuffer, i_szBuffer, l_pValue, (l_dwSize > i_szBuffer) ? i_szBuffer : l_dwSize); + o_pBuffer[i_szBuffer-1] = 0; + l_bReturn = TRUE; + + l_lblExit: + if (l_pFileInfo) + { + free(l_pFileInfo); + l_pFileInfo = NULL; + } + return l_bReturn; + }//Get_TextResource + + + //////////////////////////////////////////////////////////////////////////// + //Get_Process_Directory + static BOOL Get_Process_Directory(CWString *o_pDirectory) + { + BOOL l_bReturn = FALSE; + DWORD l_dwLength = 4096; + + if ( (NULL == o_pDirectory) + || (FALSE == o_pDirectory->Realloc(l_dwLength)) + ) + { + return l_bReturn; + } + + if (0 != GetModuleFileNameW(GetModuleHandleW(NULL), + o_pDirectory->Get(), + o_pDirectory->Max_Length()) + ) + { + wchar_t *l_pExe_Name = NULL; + + if ( (l_pExe_Name = wcsrchr(o_pDirectory->Get(), L'\\')) + || (l_pExe_Name = wcsrchr(o_pDirectory->Get(), L'/')) + ) + { + o_pDirectory->Trim((DWORD)(l_pExe_Name - o_pDirectory->Get())); + l_bReturn = TRUE; + } + } + + return l_bReturn; + }//Get_Process_Directory + + + //////////////////////////////////////////////////////////////////////////// + //Get_Process_Path + static BOOL Get_Process_Path(CWString *o_pPath) + { + BOOL l_bReturn = FALSE; + DWORD l_dwLength = 4096; + + if ( (NULL == o_pPath) + || (FALSE == o_pPath->Realloc(l_dwLength)) + ) + { + return l_bReturn; + } + + if (0 != GetModuleFileNameW(GetModuleHandleW(NULL), + o_pPath->Get(), + o_pPath->Max_Length()) + ) + { + l_bReturn = TRUE; + } + + return l_bReturn; + }//Get_Process_Path + + + //////////////////////////////////////////////////////////////////////////// + //Get_File_Size + static tUINT64 Get_File_Size(const wchar_t *i_pFile) + { + WIN32_FILE_ATTRIBUTE_DATA l_sFAD = {0}; + LARGE_INTEGER l_sSize = {0}; + + if (!GetFileAttributesExW(i_pFile, GetFileExInfoStandard, &l_sFAD)) + { + return 0; // error condition, could call GetLastError to find out more + } + + l_sSize.HighPart = l_sFAD.nFileSizeHigh; + l_sSize.LowPart = l_sFAD.nFileSizeLow; + return l_sSize.QuadPart; + }//Get_File_Size + + + //////////////////////////////////////////////////////////////////////////// + //Delete_File + static BOOL Delete_File(const wchar_t *i_pFile_Name) + { + if (NULL == i_pFile_Name) + { + return FALSE; + } + + DWORD l_dwFAttr = GetFileAttributesW(i_pFile_Name); + l_dwFAttr = l_dwFAttr & (~FILE_ATTRIBUTE_ARCHIVE); + l_dwFAttr = l_dwFAttr & (~FILE_ATTRIBUTE_READONLY); + l_dwFAttr = l_dwFAttr & (~FILE_ATTRIBUTE_SYSTEM); + SetFileAttributesW(i_pFile_Name, l_dwFAttr); + return DeleteFileW(i_pFile_Name); + }//Delete_File + + + //////////////////////////////////////////////////////////////////////////// + //GetUserDirectory + static tBOOL GetUserDirectory(CWString *o_pPath) + { + if ( (NULL == o_pPath) + || (FALSE == o_pPath->Realloc(4096)) + ) + { + return TRUE; + } + + if ( S_OK != SHGetFolderPathW(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, o_pPath->Get())) + { + return FALSE; + } + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////// + //GetUserDirectory + static tBOOL GetDirectoryParent(CWString &i_rChild, CWString &o_rParent) + { + o_rParent.Set(i_rChild.Get()); + size_t l_szDir = o_rParent.Length(); + tXCHAR *l_pDir = o_rParent.Get(); + + //cut trailing '/' or '\' + while ( (l_szDir) + && ( (TM('\\') == l_pDir[l_szDir - 1]) + || (TM('/') == l_pDir[l_szDir - 1]) + ) + ) + { + l_pDir[--l_szDir] = 0; + } + + tXCHAR *l_pTemp = wcsrchr(l_pDir, TM('\\')); + if (!l_pTemp) + { + l_pTemp = wcsrchr(l_pDir, TM('/')); + } + + if (!l_pTemp) + { + o_rParent.Set(TM("")); + return TRUE; + } + + *l_pTemp = 0; + l_pTemp--; + //removing duplicates of '\' '/' + while ( (TM('\\') == *l_pTemp) + || (TM('/') == *l_pTemp) + ) + { + *l_pTemp = 0; + l_pTemp--; + + if (l_pDir > l_pTemp) + { + break; + } + } + + return TRUE; + } + +}; + + diff --git a/p7lib/Shared/Platforms/Windows_x86/PJournal.h b/p7lib/Shared/Platforms/Windows_x86/PJournal.h new file mode 100644 index 0000000..00f8ed6 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PJournal.h @@ -0,0 +1,699 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#define FJOURNAL_FILE_BUFFER_LENGTH (0x20000) +#define FJOURNAL_FILE_BUFFER_MINIMUM_REMAINDER (0x2000) +#define FJOURNAL_THREAD_WAKEUP_INTERVAL (2500) +#define FJOURNAL_FILE_EXTENSION L"log" +#define FJOURNAL_DESCRIPTION_MAX_LENGTH (64) +#define FJOURNAL_MAX_FILES (7) + + +void __cdecl FJournal_Routine(void *i_pContext); + +// 1. Dump to the file +// 2. must have parameters and possibility to export them +// 3. should have own thread to notify about writing, every 1-5 seconds. + +class CJournal + : virtual public IJournal +{ +private: + //put volatile variables at the top, to obtain 32 bit alignment. + //Project has 8 bytes alignment by default + volatile LONG m_lReference_Counter; + + HANDLE m_hLog_File; + wchar_t *m_pJournal_Buffer; + wchar_t *m_pWrite_Buffer; + DWORD m_dwBuffer_Used; + + HANDLE m_hThread; + HANDLE m_hEvent_Exit; + HANDLE m_hEvent_Write; + + CRITICAL_SECTION m_tCS; + + SYSTEMTIME m_tTime; + wchar_t m_pTypes_Description[IJournal::eLEVEL_COUNT][FJOURNAL_DESCRIPTION_MAX_LENGTH]; + CWString m_cFile_Name; + UINT64 m_pCount[IJournal::eLEVEL_COUNT]; + + IJournal::eLevel m_eVerbosity; + + IJournal::eTime m_eTime; //ignored for a while + tBOOL m_bFunction; + tBOOL m_bType; + + BOOL m_bInitialized; + BOOL m_bError; + + DWORD m_dwMax_Files; +public: + //////////////////////////////////////////////////////////////////////////// + CJournal() + : m_lReference_Counter(1) + , m_hLog_File(INVALID_HANDLE_VALUE) + , m_pJournal_Buffer(NULL) + , m_pWrite_Buffer(NULL) + , m_dwBuffer_Used(0) + , m_hThread(NULL) + , m_hEvent_Exit(NULL) + , m_hEvent_Write(NULL) + , m_eVerbosity(IJournal::eLEVEL_TRACE) + , m_eTime(IJournal::eTIME_YYYYMMDDHHMMSSMS) + , m_bFunction(TRUE) + , m_bType(TRUE) + , m_bInitialized(FALSE) + , m_bError(FALSE) + , m_dwMax_Files(FJOURNAL_MAX_FILES) + { + memset(&m_tCS, 0, sizeof(CRITICAL_SECTION)); + memset(&m_pCount, 0, sizeof(m_pCount)); + + InitializeCriticalSection(&m_tCS); + + wcscpy_s(m_pTypes_Description[IJournal::eLEVEL_TRACE], FJOURNAL_DESCRIPTION_MAX_LENGTH, L"INFO : "); + wcscpy_s(m_pTypes_Description[IJournal::eLEVEL_DEBUG], FJOURNAL_DESCRIPTION_MAX_LENGTH, L"DEBUG: "); + wcscpy_s(m_pTypes_Description[IJournal::eLEVEL_INFO], FJOURNAL_DESCRIPTION_MAX_LENGTH, L"INFO : "); + wcscpy_s(m_pTypes_Description[IJournal::eLEVEL_WARNING], FJOURNAL_DESCRIPTION_MAX_LENGTH, L"WARN.: "); + wcscpy_s(m_pTypes_Description[IJournal::eLEVEL_ERROR], FJOURNAL_DESCRIPTION_MAX_LENGTH, L"ERROR: "); + wcscpy_s(m_pTypes_Description[IJournal::eLEVEL_CRITICAL], FJOURNAL_DESCRIPTION_MAX_LENGTH, L"CRIT.: "); + } + + //////////////////////////////////////////////////////////////////////////// + void Set_Files_Max_Count(DWORD i_dwVal) + { + m_dwMax_Files = i_dwVal; + }//Set_Files_Max_Count + + //////////////////////////////////////////////////////////////////////////// + tBOOL Initialize(const tXCHAR *i_pName) + { + if (TRUE == m_bInitialized) + { + return TRUE; + } + + if ( (NULL == i_pName) + || (TRUE == m_bError) + ) + { + return FALSE; + } + + CWString l_sDirectory; + + if (FALSE == m_bError) + { + m_pJournal_Buffer = new wchar_t[FJOURNAL_FILE_BUFFER_LENGTH]; + m_pWrite_Buffer = new wchar_t[FJOURNAL_FILE_BUFFER_LENGTH]; + if ( (NULL == m_pJournal_Buffer) || (NULL == m_pWrite_Buffer) ) + { + m_bError = TRUE; + } + } + + if (FALSE == m_bError) + { + CFSYS::Get_Process_Directory(&l_sDirectory); + l_sDirectory.Append(2, L"\\", i_pName); + + if (FALSE == CFSYS::Directory_Exists(l_sDirectory.Get())) + { + m_bError = (! CFSYS::Directory_Create(l_sDirectory.Get())); + } + } + + + if (FALSE == m_bError) + { + Remove_Old_Journals(l_sDirectory.Get(), + m_dwMax_Files, + FJOURNAL_FILE_EXTENSION + ); + + DWORD l_dwIterator = 0; + SYSTEMTIME l_tTime; + GetLocalTime(&l_tTime); + do + { + swprintf_s(m_pJournal_Buffer, + FJOURNAL_FILE_BUFFER_LENGTH, + L"%s\\%04d_%02d_%02d-%02d_%02d_%02d-%d.%s", + l_sDirectory.Get(), + (int)l_tTime.wYear, + (int)l_tTime.wMonth, + (int)l_tTime.wDay, + (int)l_tTime.wHour, + (int)l_tTime.wMinute, + (int)l_tTime.wSecond, + (int)l_dwIterator++, + FJOURNAL_FILE_EXTENSION + ); + } while (CFSYS::File_Exists(m_pJournal_Buffer)); + + m_cFile_Name.Set((wchar_t*)m_pJournal_Buffer); + + m_hLog_File = CreateFileW(m_pJournal_Buffer, + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if ( (NULL == m_hLog_File) + || (INVALID_HANDLE_VALUE == m_hLog_File) + ) + { + m_hLog_File = INVALID_HANDLE_VALUE; + m_bError = TRUE; + } + } + + if (FALSE == m_bError) + { + m_hEvent_Exit = CreateEventW(NULL, FALSE, FALSE, NULL); + m_hEvent_Write = CreateEventW(NULL, TRUE, FALSE, NULL); + if ( (NULL == m_hEvent_Exit) || (NULL == m_hEvent_Write) ) + { + m_bError = TRUE; + } + } + + if (FALSE == m_bError) + { + m_pJournal_Buffer[0] = 0xFEFF; + m_dwBuffer_Used = 1; + + m_hThread = (void*)_beginthread(&Routine_Entry_Point, 0, this); + if (NULL == m_hThread) + { + m_bError = TRUE; + } + } + + if (FALSE == m_bError) + { + m_bInitialized = TRUE; + } + + return (! m_bError); + } + + //////////////////////////////////////////////////////////////////////////// + void Set_Verbosity(IJournal::eLevel i_eVerbosity) + { + EnterCriticalSection(&m_tCS); + m_eVerbosity = i_eVerbosity; + LeaveCriticalSection(&m_tCS); + } + + //////////////////////////////////////////////////////////////////////////// + void Set_Format(IJournal::eTime i_eTime, tBOOL i_bFunction, tBOOL i_bType) + { + EnterCriticalSection(&m_tCS); + m_eTime = i_eTime; + m_bFunction = i_bFunction; + m_bType = i_bType; + LeaveCriticalSection(&m_tCS); + } + + //////////////////////////////////////////////////////////////////////////// + IJournal::eLevel Get_Verbosity() + { + IJournal::eLevel l_eResult; + EnterCriticalSection(&m_tCS); + l_eResult = m_eVerbosity; + LeaveCriticalSection(&m_tCS); + + return l_eResult; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Log(IJournal::eLevel i_eType, + IJournal::hModule i_hModule, + const char *i_pFile, + const char *i_pFunction, + tUINT32 i_dwLine, + const tXCHAR *i_pFormat, + ... + ) + { + tBOOL l_bResult = TRUE; + int l_iCount = 0; + wchar_t *l_pBuffer = NULL; + + if ( (FALSE == m_bInitialized) + || (NULL == i_pFormat) + || (i_eType >= IJournal::eLEVEL_COUNT) + ) + { + return FALSE; + } + + EnterCriticalSection(&m_tCS); + + m_pCount[i_eType]++; + + if (i_eType < m_eVerbosity) + { + l_bResult = FALSE; + goto l_lExit; + } + + if ( (m_dwBuffer_Used >= FJOURNAL_FILE_BUFFER_LENGTH) + || (FJOURNAL_FILE_BUFFER_MINIMUM_REMAINDER >= (FJOURNAL_FILE_BUFFER_LENGTH - m_dwBuffer_Used) ) + ) + { + SetEvent(m_hEvent_Write); + + while (WAIT_OBJECT_0 == WaitForSingleObject(m_hEvent_Write, 0)) + { + Sleep(5); + } + } + + + if ( (l_bResult) + && (i_pFunction) + && (m_bFunction) + ) + { + l_pBuffer = m_pJournal_Buffer + m_dwBuffer_Used; + + while (*i_pFunction) + { + (*l_pBuffer++) = (*i_pFunction++); + m_dwBuffer_Used ++; + } + + l_iCount = swprintf_s(m_pJournal_Buffer + m_dwBuffer_Used, + FJOURNAL_FILE_BUFFER_LENGTH - m_dwBuffer_Used, + L"() Ln %04d : ", (int)i_dwLine + ); + if (0 > l_iCount) + { + l_bResult = FALSE; + } + else + { + m_dwBuffer_Used += l_iCount; + } + + l_pBuffer = m_pJournal_Buffer + m_dwBuffer_Used; + (*l_pBuffer++) = 13; + (*l_pBuffer++) = 10; + m_dwBuffer_Used += 2; + } + + if (l_bResult) + { + GetLocalTime(&m_tTime); + l_iCount = swprintf_s(m_pJournal_Buffer + m_dwBuffer_Used, + FJOURNAL_FILE_BUFFER_LENGTH - m_dwBuffer_Used, + L"[%04d.%02d.%02d %02d:%02d:%02d.%03d] %s ", + (int)m_tTime.wYear, (int)m_tTime.wMonth, (int)m_tTime.wDay, + (int)m_tTime.wHour, (int)m_tTime.wMinute, (int)m_tTime.wSecond, (int)m_tTime.wMilliseconds, + m_bType ? m_pTypes_Description[i_eType] : L"" + ); + if (0 > l_iCount) + { + l_bResult = FALSE; + } + else + { + m_dwBuffer_Used += l_iCount; + } + } + + if (l_bResult) + { + va_list l_pArgList; + va_start(l_pArgList, i_pFormat); + size_t l_stRemaining = 0; + + if (S_OK == StringCbVPrintfExW(m_pJournal_Buffer + m_dwBuffer_Used, + (FJOURNAL_FILE_BUFFER_LENGTH - m_dwBuffer_Used) * sizeof(wchar_t), + NULL, + &l_stRemaining, + STRSAFE_IGNORE_NULLS, + i_pFormat, + l_pArgList + ) + ) + { + m_dwBuffer_Used = FJOURNAL_FILE_BUFFER_LENGTH - (DWORD)(l_stRemaining / sizeof(wchar_t)); + } + else + { + l_bResult = FALSE; + } + + va_end(l_pArgList); + } + + if (l_bResult) + { + l_pBuffer = m_pJournal_Buffer + m_dwBuffer_Used; + (*l_pBuffer++) = 13; + (*l_pBuffer++) = 10; + m_dwBuffer_Used += 2; + } + + l_lExit: + + LeaveCriticalSection(&m_tCS); + + return l_bResult; + } + + //////////////////////////////////////////////////////////////////////////// + wchar_t *Get_File_Name() + { + if (FALSE == m_bInitialized) + { + return NULL; + } + + return m_cFile_Name.Get(); + } + + //////////////////////////////////////////////////////////////////////////// + tUINT64 Get_Count(IJournal::eLevel i_eType) + { + UINT64 l_qwReturn = 0ULL; + if (i_eType >= IJournal::eLEVEL_COUNT) + { + return 0ULL; + } + + EnterCriticalSection(&m_tCS); + l_qwReturn = m_pCount[i_eType]; + LeaveCriticalSection(&m_tCS); + + return l_qwReturn; + } + + //////////////////////////////////////////////////////////////////////////// + tINT32 Add_Ref() + { + return InterlockedIncrement(&m_lReference_Counter); + } + + //////////////////////////////////////////////////////////////////////////// + tINT32 Release() + { + volatile tINT32 l_iRCnt = InterlockedDecrement(&m_lReference_Counter); + + if ( 0 >= l_iRCnt) + { + delete this; + } + + return l_iRCnt; + } + + //////////////////////////////////////////////////////////////////////////// + BOOL Get_Initialized() + { + return m_bInitialized; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Register_Thread(const tXCHAR *i_pName, tUINT32 i_dwThreadId) + { + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Unregister_Thread(tUINT32 i_dwThreadId) + { + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + tBOOL Register_Module(const tXCHAR *i_pName, IJournal::hModule *o_hModule) + { + if (o_hModule) + { + *o_hModule = NULL; + } + + return FALSE; + } + +protected: + //////////////////////////////////////////////////////////////////////////// + static void __cdecl Routine_Entry_Point(void *i_pContext) + { + CJournal * l_pFJournal = (CJournal *)i_pContext; + if (l_pFJournal) + { + l_pFJournal->Routine(); + } + _endthread(); + } + + //////////////////////////////////////////////////////////////////////////// + void Routine() + { + BOOL l_bExit = FALSE; + HANDLE l_pEvents[] = {m_hEvent_Exit, m_hEvent_Write}; + DWORD l_dwWFMO_result = 0; + DWORD l_dwSize = 0; + + while (FALSE == l_bExit) + { + l_dwWFMO_result = WaitForMultipleObjects(sizeof(l_pEvents)/sizeof(l_pEvents[0]), + l_pEvents, + FALSE, + FJOURNAL_THREAD_WAKEUP_INTERVAL + ); //Process events + + + // Exit signal + if (WAIT_OBJECT_0 == l_dwWFMO_result) + { + l_dwSize = Copy_Bufer(TRUE); + if (l_dwSize) + { + Write((BYTE*)m_pWrite_Buffer, l_dwSize); + } + + l_bExit = TRUE; + } + else if ( (WAIT_OBJECT_0 + 1) == l_dwWFMO_result)// we have received signal for write + { + l_dwSize = Copy_Bufer(FALSE); + ResetEvent(m_hEvent_Write); + + if ( (l_dwSize) && (FALSE == Write((BYTE*)m_pWrite_Buffer, l_dwSize)) ) + { + l_bExit = TRUE; + } + } + else if (WAIT_TIMEOUT == l_dwWFMO_result) + { + l_dwSize = Copy_Bufer(TRUE); + + if ( (l_dwSize) && (FALSE == Write((BYTE*)m_pWrite_Buffer, l_dwSize)) ) + { + l_bExit = TRUE; + } + } + } + + m_hThread = NULL; + } + +private: + //////////////////////////////////////////////////////////////////////////// + DWORD Copy_Bufer(BOOL i_bLock) + { + DWORD l_dwResult = 0; + + if (i_bLock) + { + EnterCriticalSection(&m_tCS); + } + + if (m_dwBuffer_Used) + { + l_dwResult = m_dwBuffer_Used * sizeof(wchar_t); + memcpy_s(m_pWrite_Buffer, FJOURNAL_FILE_BUFFER_LENGTH * sizeof(wchar_t), m_pJournal_Buffer, l_dwResult); + m_dwBuffer_Used = 0; + } + + if (i_bLock) + { + LeaveCriticalSection(&m_tCS); + } + + return l_dwResult; + } + + //////////////////////////////////////////////////////////////////////////// + BOOL Write(BYTE *i_pBuffer, DWORD i_dwSize) + { + BOOL l_bResult = TRUE; + DWORD l_dwReturned = 0; + DWORD l_dwWriten = 0; + + if ( (0 >= i_dwSize) || (NULL == i_pBuffer) ) + { + return FALSE; + } + + while ( l_dwWriten != i_dwSize ) + { + l_dwReturned = 0; + if ( 0 == WriteFile(m_hLog_File, + i_pBuffer + l_dwWriten, + i_dwSize - l_dwWriten, + &l_dwReturned, + NULL) + ) + { + i_dwSize = 0; + l_dwWriten = 0; + l_bResult = FALSE; + } + else + { + l_dwWriten += l_dwReturned; + } + } //while + + return l_bResult; + } + + //////////////////////////////////////////////////////////////////////////// + BOOL Remove_Old_Journals(wchar_t *i_pFolder, DWORD i_dwMax_Files, const wchar_t *i_pExtension) + { + wchar_t l_pFileName[ MAX_PATH ] = L"9999"; + DWORD l_dwPrev_Error_Mode = 0; + WIN32_FIND_DATAW l_tFind_Info; + HANDLE l_hFind = INVALID_HANDLE_VALUE; + DWORD l_dwCount = 0; + BOOL l_bResult = TRUE; + + if ( (NULL == i_pFolder) || (NULL == i_pExtension) ) + { + return FALSE; + } + + l_dwPrev_Error_Mode = SetErrorMode(SEM_FAILCRITICALERRORS); + + l_dwCount = i_dwMax_Files + 1; + + while ( (l_dwCount > i_dwMax_Files) && (l_bResult) ) + { + l_dwCount = 0; + + swprintf_s(m_pJournal_Buffer, FJOURNAL_FILE_BUFFER_LENGTH, L"%s\\*.%s", i_pFolder, i_pExtension); + + l_hFind = FindFirstFileW(m_pJournal_Buffer, &l_tFind_Info); + + while(INVALID_HANDLE_VALUE != l_hFind) + { + if (0 == (l_tFind_Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + l_dwCount ++; + if (0 <= _wcsicmp(l_pFileName, l_tFind_Info.cFileName)) + { + wcscpy_s(l_pFileName, MAX_PATH, l_tFind_Info.cFileName); + } + + if ( ! FindNextFileW(l_hFind, &l_tFind_Info)) + { + FindClose(l_hFind); + l_hFind = INVALID_HANDLE_VALUE; + } + } + } //while(INVALID_HANDLE_VALUE != hFind) + + SetErrorMode(l_dwPrev_Error_Mode); + + if (l_dwCount > i_dwMax_Files) + { + swprintf_s(m_pJournal_Buffer, FJOURNAL_FILE_BUFFER_LENGTH, L"%s\\%s", i_pFolder, l_pFileName); + + DWORD l_dwFAttr = GetFileAttributesW(m_pJournal_Buffer); + l_dwFAttr = l_dwFAttr & (~FILE_ATTRIBUTE_ARCHIVE); + l_dwFAttr = l_dwFAttr & (~FILE_ATTRIBUTE_READONLY); + l_dwFAttr = l_dwFAttr & (~FILE_ATTRIBUTE_SYSTEM); + SetFileAttributesW(m_pJournal_Buffer, l_dwFAttr); + l_bResult = DeleteFileW(m_pJournal_Buffer); + l_dwCount --; + wcscpy_s(l_pFileName, MAX_PATH, L"9999"); + } + } + + return l_bResult; + } + + //////////////////////////////////////////////////////////////////////////// + virtual ~CJournal() //use Release() instead + { + if (m_hThread) + { + if (m_hEvent_Exit) + { + SetEvent(m_hEvent_Exit); + if (WAIT_TIMEOUT == WaitForSingleObject(m_hThread, 150000)) + { + OutputDebugStringW(L"~CFJournal::Thread exit failed !\n"); + } + CloseHandle(m_hEvent_Exit); + m_hEvent_Exit = NULL; + } + } + + if (m_hEvent_Write) + { + CloseHandle(m_hEvent_Write); + m_hEvent_Write = NULL; + } + + if (INVALID_HANDLE_VALUE != m_hLog_File) + { + CloseHandle(m_hLog_File); + m_hLog_File = INVALID_HANDLE_VALUE; + } + + if (m_pJournal_Buffer) + { + delete [] m_pJournal_Buffer; + m_pJournal_Buffer = NULL; + } + + if (m_pWrite_Buffer) + { + delete [] m_pWrite_Buffer; + m_pWrite_Buffer = NULL; + } + + DeleteCriticalSection(&m_tCS); + } + +}; diff --git a/p7lib/Shared/Platforms/Windows_x86/PLock.h b/p7lib/Shared/Platforms/Windows_x86/PLock.h new file mode 100644 index 0000000..6a45a8b --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PLock.h @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +/////////////////////////////////////////////////////////////////////////////// +typedef CRITICAL_SECTION tLOCK; + + +#define LOCK_CREATE(i_Lock) InitializeCriticalSection(&i_Lock) +#define LOCK_DESTROY(i_Lock) DeleteCriticalSection(&i_Lock) + +#define LOCK_ENTER(i_Lock) EnterCriticalSection(&i_Lock) +#define LOCK_EXIT(i_Lock) LeaveCriticalSection(&i_Lock) +#define LOCK_TRY(i_Lock) TryEnterCriticalSection(&i_Lock) diff --git a/p7lib/Shared/Platforms/Windows_x86/PMEvent.h b/p7lib/Shared/Platforms/Windows_x86/PMEvent.h new file mode 100644 index 0000000..b5d2e4a --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PMEvent.h @@ -0,0 +1,216 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + + +//////////////////////////////////////////////////////////////////////////////// +class CMEvent + : virtual public IMEvent +{ + struct sMEvent + { + eMEvent_Type eType; + HANDLE hEvent; + }; + + tUINT8 m_bCount; + sMEvent *m_pEvents; + tBOOL m_bInit; + HANDLE *m_pHandles; +public: + //////////////////////////////////////////////////////////////////////////// + //CMEvent + CMEvent() + : m_bCount(0) + , m_pEvents(NULL) + , m_bInit(FALSE) + , m_pHandles(NULL) + { + }//CMEvent + + + //////////////////////////////////////////////////////////////////////////// + //~CMEvent + virtual ~CMEvent() + { + Cleanup(); + + m_bCount = 0; + }//~CMEvent + + + //////////////////////////////////////////////////////////////////////////// + //Init + tBOOL Init(tUINT8 i_bCount, ...) + { + if ( (TRUE == m_bInit) + || (0 >= i_bCount) + ) + { + return FALSE; + } + + va_list l_pVA; + tUINT8 l_bIDX = 0; + + m_pEvents = new sMEvent[i_bCount]; + if (NULL == m_pEvents) + { + goto l_lExit; + } + + m_pHandles = new HANDLE[i_bCount]; + if (NULL == m_pHandles) + { + goto l_lExit; + } + + memset(m_pEvents, 0, sizeof(sMEvent) * i_bCount); + + va_start(l_pVA, i_bCount); + while (l_bIDX < i_bCount) + { + m_pEvents[l_bIDX].eType = (eMEvent_Type)va_arg(l_pVA, int); //Real type is "eMEvent_Type", MinGW warning + + if (EMEVENT_SINGLE_AUTO == m_pEvents[l_bIDX].eType) + { + m_pEvents[l_bIDX].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + } + else if (EMEVENT_SINGLE_MANUAL == m_pEvents[l_bIDX].eType) + { + m_pEvents[l_bIDX].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + } + else if (EMEVENT_MULTI == m_pEvents[l_bIDX].eType) + { + m_pEvents[l_bIDX].hEvent = CreateSemaphore(NULL, 0, 0xFFFFFF, NULL); + } + + m_pHandles[l_bIDX] = m_pEvents[l_bIDX].hEvent; + + l_bIDX++; + } + + va_end(l_pVA); + + m_bInit = TRUE; + m_bCount = i_bCount; + + l_lExit: + + if (FALSE == m_bInit) + { + Cleanup(); + } + + return m_bInit; + }//Init + + + //////////////////////////////////////////////////////////////////////////// + //Set + tBOOL Set(tUINT32 i_dwID) + { + if (i_dwID >= m_bCount) + { + return FALSE; + } + + if (EMEVENT_MULTI == m_pEvents[i_dwID].eType) + { + ReleaseSemaphore(m_pEvents[i_dwID].hEvent, 1, NULL); + } + else + { + SetEvent(m_pEvents[i_dwID].hEvent); + } + + return TRUE; + }//Set + + + //////////////////////////////////////////////////////////////////////////// + //Clr + tBOOL Clr(tUINT32 i_dwID) + { + if ( (i_dwID >= m_bCount) + || (EMEVENT_SINGLE_MANUAL != m_pEvents[i_dwID].eType) + ) + { + return FALSE; + } + + ResetEvent(m_pEvents[i_dwID].hEvent); + return TRUE; + }//Clr + + //////////////////////////////////////////////////////////////////////////// + //Wait + tUINT32 Wait() + { + return Wait(INFINITE); + }//Wait + + //////////////////////////////////////////////////////////////////////////// + //Wait + tUINT32 Wait(tUINT32 i_dwMSec) + { + DWORD l_dwRes = WaitForMultipleObjects(m_bCount, + m_pHandles, + FALSE, + i_dwMSec + ); + + if ( (WAIT_TIMEOUT == l_dwRes) + || (WAIT_FAILED == l_dwRes) + ) + { + return MEVENT_TIME_OUT; + } + + + return (MEVENT_SIGNAL_0 + (l_dwRes - WAIT_OBJECT_0)); + }//Wait + +private: + //////////////////////////////////////////////////////////////////////////// + //Cleanup + void Cleanup() + { + if (m_pHandles) + { + delete [] m_pHandles; + m_pHandles = NULL; + } + + if (m_pEvents) + { + for (tUINT32 l_dwI = 0; l_dwI < m_bCount; l_dwI++) + { + if (m_pEvents[l_dwI].hEvent) + { + CloseHandle(m_pEvents[l_dwI].hEvent); + m_pEvents[l_dwI].hEvent = NULL; + } + } + + delete [] m_pEvents; + m_pEvents = NULL; + } + }//Cleanup +}; diff --git a/p7lib/Shared/Platforms/Windows_x86/PPerformanceInfo.h b/p7lib/Shared/Platforms/Windows_x86/PPerformanceInfo.h new file mode 100644 index 0000000..714e483 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PPerformanceInfo.h @@ -0,0 +1,215 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PPERFORMANCE_INFO_H +#define PPERFORMANCE_INFO_H + +#include "IPerformanceInfo.h" + +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CPerformanceInfo + : public IPerformanceInfo +{ + volatile tINT32 m_iRCnt; + PDH_STATUS m_hPdhStatus; + HQUERY m_hPdhQuery; + HCOUNTER m_hPdhCounter[IPerformanceInfo::eCounterTotal]; + SYSTEM_INFO m_sSysInfo; + +public: + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + CPerformanceInfo(const tXCHAR *i_pProcessName) + : m_iRCnt(1) + , m_hPdhStatus(ERROR_SUCCESS) + , m_hPdhQuery(NULL) + { + tXCHAR l_pExeName[256]; + CWString l_cPhdPath; + GetSystemInfo( &m_sSysInfo ); + memset(m_hPdhCounter, 0, sizeof(m_hPdhCounter)); + if (!m_sSysInfo.dwNumberOfProcessors) + { + m_sSysInfo.dwNumberOfProcessors = 1; + } + + if (GetModuleBaseNameW(GetCurrentProcess(), NULL, l_pExeName, LENGTH(l_pExeName))) + { + tXCHAR *l_pExt = wcsrchr(l_pExeName, TM('.')); + if (l_pExt) + { + *l_pExt = 0; + } + } + else + { + PStrCpy(l_pExeName, LENGTH(l_pExeName), i_pProcessName); + } + + l_cPhdPath.Realloc(4096); + + //////////////////////////////////////////////////////////////////////////// + //create PHD counters + //If counters is missing == PDH_CSTATUS_NO_OBJECT + //http://blogs.msdn.com/b/martinv/archive/2008/11/18/missing-performance-counters.aspx + //C:\Windows\System32> lodctr /R + //After that all Performance Counters were available again! + if (ERROR_SUCCESS == PdhOpenQuery(NULL, NULL, &m_hPdhQuery)) + { + m_hPdhStatus = PdhAddEnglishCounterW(m_hPdhQuery, + TM("\\Processor(_Total)\\% Processor Time"), + 0, + &m_hPdhCounter[IPerformanceInfo::eCounterSystemCpu]); + if (ERROR_SUCCESS != m_hPdhStatus) + { + m_hPdhCounter[IPerformanceInfo::eCounterSystemCpu] = NULL; + } + + l_cPhdPath.Set(TM("")); + swprintf_s(l_cPhdPath.Get(), l_cPhdPath.Max_Length(), TM("\\Process(%s)\\%% Processor Time"), l_pExeName); + if (ERROR_SUCCESS != PdhAddEnglishCounterW(m_hPdhQuery, l_cPhdPath.Get(), 0, &m_hPdhCounter[IPerformanceInfo::eCounterProcessCpu])) + { + m_hPdhCounter[IPerformanceInfo::eCounterProcessCpu] = NULL; + } + + l_cPhdPath.Set(TM("")); + swprintf_s(l_cPhdPath.Get(), l_cPhdPath.Max_Length(), TM("\\Process(%s)\\Handle Count"), l_pExeName); + if (ERROR_SUCCESS != PdhAddEnglishCounterW(m_hPdhQuery, l_cPhdPath.Get(), 0, &m_hPdhCounter[IPerformanceInfo::eCounterProcessHandles])) + { + m_hPdhCounter[IPerformanceInfo::eCounterProcessHandles] = NULL; + } + + l_cPhdPath.Set(TM("")); + swprintf_s(l_cPhdPath.Get(), l_cPhdPath.Max_Length(), TM("\\Process(%s)\\Thread Count"), l_pExeName); + if (ERROR_SUCCESS != PdhAddEnglishCounterW(m_hPdhQuery, l_cPhdPath.Get(), 0, &m_hPdhCounter[IPerformanceInfo::eCounterProcessThreads])) + { + m_hPdhCounter[IPerformanceInfo::eCounterProcessThreads] = NULL; + } + + l_cPhdPath.Set(TM("")); + swprintf_s(l_cPhdPath.Get(), l_cPhdPath.Max_Length(), TM("\\Process(%s)\\Working Set"), l_pExeName); + if (ERROR_SUCCESS != PdhAddEnglishCounterW(m_hPdhQuery, l_cPhdPath.Get(), 0, &m_hPdhCounter[IPerformanceInfo::eCounterProcessMemory])) + { + m_hPdhCounter[IPerformanceInfo::eCounterProcessMemory] = NULL; + } + }//if (ERROR_SUCCESS == PdhOpenQuery(NULL, NULL, &m_hPdhQuery)) + + + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual ~CPerformanceInfo() + { + if (m_hPdhCounter[IPerformanceInfo::eCounterProcessCpu]) + { + PdhRemoveCounter(m_hPdhCounter[IPerformanceInfo::eCounterProcessCpu]); + m_hPdhCounter[IPerformanceInfo::eCounterProcessCpu] = NULL; + } + + if (m_hPdhCounter[IPerformanceInfo::eCounterSystemCpu]) + { + PdhRemoveCounter(m_hPdhCounter[IPerformanceInfo::eCounterSystemCpu]); + m_hPdhCounter[IPerformanceInfo::eCounterSystemCpu] = NULL; + } + + + if (m_hPdhCounter[IPerformanceInfo::eCounterProcessHandles]) + { + PdhRemoveCounter(m_hPdhCounter[IPerformanceInfo::eCounterProcessHandles]); + m_hPdhCounter[IPerformanceInfo::eCounterProcessHandles] = NULL; + } + + if (m_hPdhCounter[IPerformanceInfo::eCounterProcessThreads]) + { + PdhRemoveCounter(m_hPdhCounter[IPerformanceInfo::eCounterProcessThreads]); + m_hPdhCounter[IPerformanceInfo::eCounterProcessThreads] = NULL; + } + + if (m_hPdhCounter[IPerformanceInfo::eCounterProcessMemory]) + { + PdhRemoveCounter(m_hPdhCounter[IPerformanceInfo::eCounterProcessMemory]); + m_hPdhCounter[IPerformanceInfo::eCounterProcessMemory] = NULL; + } + + if (m_hPdhQuery) + { + PdhCloseQuery(m_hPdhQuery); + m_hPdhQuery = NULL; + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tBOOL Refresh() + { + if ( (m_hPdhQuery) + && (ERROR_SUCCESS == PdhCollectQueryData(m_hPdhQuery)) + ) + { + return TRUE; + } + + return FALSE; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tINT64 Get(IPerformanceInfo::eCounter i_eCounter) + { + PDH_FMT_COUNTERVALUE l_tPdhValue = {0}; + + if ( (i_eCounter >= IPerformanceInfo::eCounterTotal) + || (!m_hPdhCounter[i_eCounter]) + ) + { + return 0; + } + + if (ERROR_SUCCESS == PdhGetFormattedCounterValue(m_hPdhCounter[i_eCounter], PDH_FMT_LARGE, NULL, &l_tPdhValue)) + { + if (IPerformanceInfo::eCounterProcessCpu == i_eCounter) + { + l_tPdhValue.largeValue /= m_sSysInfo.dwNumberOfProcessors; + } + } + + return l_tPdhValue.largeValue; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tINT32 Add_Ref() + { + return ATOMIC_INC(&m_iRCnt); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + tINT32 Release() + { + volatile tINT32 l_iReturn = ATOMIC_DEC(&m_iRCnt); + + if (0 >= l_iReturn) + { + delete this; + } + + return l_iReturn; + } +}; + +#endif //PPERFORMANCE_INFO_H diff --git a/p7lib/Shared/Platforms/Windows_x86/PProcess.h b/p7lib/Shared/Platforms/Windows_x86/PProcess.h new file mode 100644 index 0000000..179ba37 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PProcess.h @@ -0,0 +1,312 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +class CProc +{ +public: + /////////////////////////////////////////////////////////////////////////////// + //Get_ArgV + static tXCHAR **Get_ArgV(tINT32 *o_pCount) + { + return Get_ArgV(GetCommandLineW(), o_pCount); + }//Get_ArgV + + + /////////////////////////////////////////////////////////////////////////////// + //Get_ArgV + static tXCHAR **Get_ArgV(const tXCHAR *i_pCmdLine, tINT32 *o_pCount) + { + tINT32 l_iLen = 0;//strlen(i_pCmdLine); + tXCHAR *l_pBuffer = NULL;//new tXCHAR[l_iLen]; + tXCHAR **l_pReturn = NULL; + tBOOL l_bNew = TRUE; + tBOOL l_bStr = FALSE; + tINT32 l_iIDX = 0; + + if ( (NULL == i_pCmdLine) + || (NULL == o_pCount) + ) + { + goto l_lblExit; + } + + l_iLen = (tINT32)wcslen(i_pCmdLine) + 1; + l_pBuffer = new tXCHAR[l_iLen]; + + if (NULL == l_pBuffer) + { + goto l_lblExit; + } + + for (tINT32 l_iI = 0; l_iI < l_iLen; l_iI++) + { + if (TM('\"') == i_pCmdLine[l_iI]) + { + l_bStr = ! l_bStr; + } + else + { + if ( (TM(' ') == i_pCmdLine[l_iI]) + && (!l_bStr) + ) + { + l_pBuffer[l_iIDX++] = 0; + } + else + { + l_pBuffer[l_iIDX++] = i_pCmdLine[l_iI]; + } + + } + } + + l_iLen = l_iIDX; + + //calculate count of items////////////////////////////////////////////////// + *o_pCount = 0; + for (tINT32 l_iI = 0; l_iI < l_iLen; l_iI++) + { + if ( (0 == l_pBuffer[l_iI]) + || ((l_iI + 1) == l_iLen) + ) + { + (*o_pCount) ++; + } + } + + if (0 >= *o_pCount) + { + goto l_lblExit; + } + + //allocate result/////////////////////////////////////////////////////////// + l_pReturn = new tXCHAR*[*o_pCount]; + + if (NULL == l_pReturn) + { + goto l_lblExit; + } + + //fill result/////////////////////////////////////////////////////////////// + l_bNew = TRUE; + l_iIDX = 0; + for (tINT32 l_iI = 0; l_iI < l_iLen; l_iI++) + { + if (l_bNew) + { + l_pReturn[l_iIDX++] = &l_pBuffer[l_iI]; + l_bNew = FALSE; + } + + if (0 == l_pBuffer[l_iI]) + { + l_bNew = TRUE; + } + } + + l_lblExit: + + return l_pReturn; + // return = CommandLineToArgvW(i_pCmdLine, o_pCount); + }//Get_ArgV + + + /////////////////////////////////////////////////////////////////////////////// + //Free_ArgV + static void Free_ArgV(tXCHAR **i_pArgV) + { + if (NULL == i_pArgV) + { + return; + } + + if (i_pArgV[0]) + { + delete [] i_pArgV[0]; + } + + delete [] i_pArgV; + //LocalFree(i_pArgV); + }//Free_ArgV + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Time() + //return a 64-bit value divided into 2 parts representing the number of + //100-nanosecond intervals since January 1, 1601 (UTC). + static tBOOL Get_Process_Time(tUINT32 *o_pHTime, tUINT32 *o_pLTime) + { + FILETIME l_tProcess_Time = {0}; + FILETIME l_tStub_01 = {0}; + FILETIME l_tStub_02 = {0}; + FILETIME l_tStub_03 = {0}; + + GetProcessTimes(GetCurrentProcess(), + &l_tProcess_Time, + &l_tStub_01, + &l_tStub_02, + &l_tStub_03 + ); + + *o_pHTime = l_tProcess_Time.dwHighDateTime; + *o_pLTime = l_tProcess_Time.dwLowDateTime; + + return TRUE; + }//Get_Process_Time() + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Name + static tBOOL Get_Process_Name(tWCHAR *o_pName, tINT32 i_iMax_Len) + { + BOOL l_bReturn = FALSE; + const tUINT32 l_dwMax_Len = 32768; + wchar_t *l_pProcess_Path = NULL; + wchar_t *l_pProcess_Name = NULL; + + if ( (NULL == o_pName) + || (64 >= i_iMax_Len) + ) + { + return FALSE; + } + + l_pProcess_Path = new wchar_t[l_dwMax_Len]; + + if (NULL == l_pProcess_Path) + { + return FALSE; + } + + if (GetModuleFileNameW(GetModuleHandleW(NULL), + l_pProcess_Path, + l_dwMax_Len + ) + ) + { + if ( (l_pProcess_Name = wcsrchr(l_pProcess_Path, L'\\')) + || (l_pProcess_Name = wcsrchr(l_pProcess_Path, L'/')) + ) + { + l_pProcess_Name ++; + l_bReturn = TRUE; + } + } + + + if (l_bReturn) + { + wcscpy_s((wchar_t*)o_pName, i_iMax_Len, l_pProcess_Name); + } + + delete [] l_pProcess_Path; + + return l_bReturn; + }//Get_Process_Name + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Name + static tBOOL Get_Process_Name(tACHAR *o_pName, tINT32 i_iMax_Len) + { + const tINT32 l_iSize = 128; + tWCHAR l_pName[l_iSize]; + + if (Get_Process_Name(l_pName, l_iSize)) + { + Convert_UTF16_To_UTF8(l_pName, o_pName, (tUINT32)i_iMax_Len); + } + else + { + strcpy_s(o_pName, (rsize_t)i_iMax_Len, "Unknown:Error"); + } + + return true; + }//Get_Process_Name + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_Path + static tBOOL Get_Process_Path(tXCHAR *o_pPath, size_t i_szName) + { + BOOL l_bReturn = FALSE; + wchar_t *l_pName = NULL; + + if ( (NULL == o_pPath) + || (256 >= i_szName) + ) + { + return FALSE; + } + + if (GetModuleFileNameW(GetModuleHandleW(NULL), + o_pPath, + (DWORD)i_szName + ) + ) + { + if ( (l_pName = wcsrchr(o_pPath, L'\\')) + || (l_pName = wcsrchr(o_pPath, L'/')) + ) + { + l_pName ++; + l_pName[0] = 0; + l_bReturn = TRUE; + } + } + + return l_bReturn; + }//Get_Process_Path + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Process_ID + static tUINT32 Get_Process_ID() + { + return GetCurrentProcessId(); + }//Get_Process_ID + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Thread_Id + static tUINT32 Get_Thread_Id() + { + return GetCurrentThreadId(); + }//Get_Thread_Id + + + //////////////////////////////////////////////////////////////////////////////// + //Get_Processor + static __forceinline tUINT32 Get_Processor() + { + #if defined(GTX64) || !defined(_MSC_VER) + //return 0xFFFF; //don't know how to get processor number ... yet. + return GetCurrentProcessorNumber(); + #else + _asm + { + mov eax, 1 + cpuid + shr ebx, 24 + mov eax, ebx + } + #endif + }//Get_Processor +}; diff --git a/p7lib/Shared/Platforms/Windows_x86/PShared.h b/p7lib/Shared/Platforms/Windows_x86/PShared.h new file mode 100644 index 0000000..63a23d7 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PShared.h @@ -0,0 +1,607 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#define SHARED_SEM_NULL NULL + + +//////////////////////////////////////////////////////////////////////////////// +//CShared +class CShared +{ + struct sShared + { + HANDLE hMemory; + HANDLE hMutex; + tXCHAR *pName; + }; + + enum eType + { + ETYPE_MUTEX = 0, + ETYPE_FILE , + ETYPE_MAX + }; + +public: + typedef sShared *hShared; + typedef HANDLE hSem; + + enum eLock + { + E_OK, + E_TIMEOUT, + E_ERROR, + E_NOT_EXISTS + }; + + //////////////////////////////////////////////////////////////////////////// + //CShared::Create + static tBOOL Create(CShared::hShared *o_pHandle, + const tXCHAR *i_pName, + const tUINT8 *i_pData, + tUINT16 i_wSize + ) + { + sShared *l_pShared = NULL; + tBOOL l_bReturn = TRUE; + DWORD l_dwLen = 0; + wchar_t *l_pName = NULL; + BOOL l_bRelease = FALSE; + tUINT8 *l_pBuffer = NULL; + + + if ( (NULL == i_pName) + || (NULL == i_pData) + || (0 >= i_wSize) + || (NULL == o_pHandle) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_pShared = new sShared; + if (NULL == l_pShared) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + memset(l_pShared, 0, sizeof(sShared)); + + l_dwLen = (DWORD)wcslen(i_pName) + 128; + l_pName = (wchar_t*)malloc(sizeof(wchar_t) * l_dwLen); + l_pShared->pName = PStrDub(i_pName); + + if ( (NULL == l_pName) + || (NULL == l_pShared->pName) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + + //////////////////////////////////////////////////////////////////////////// + //create mutex and own it + Create_Name(l_pName, l_dwLen, ETYPE_MUTEX, i_pName); + + l_pShared->hMutex = CreateMutexW(NULL, TRUE, l_pName); + if ( (NULL == l_pShared->hMutex) + || (ERROR_ALREADY_EXISTS == GetLastError()) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_bRelease = TRUE; + + //////////////////////////////////////////////////////////////////////////// + //create shared memory object + Create_Name(l_pName, l_dwLen, ETYPE_FILE, i_pName); + + l_pShared->hMemory = CreateFileMappingW(INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order tUINT32) + i_wSize, // maximum object size (low-order tUINT32) + l_pName // name of mapping object + ); + + if ( (NULL == l_pShared->hMemory) + || (ERROR_ALREADY_EXISTS == GetLastError()) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_pBuffer = (tUINT8*)MapViewOfFile(l_pShared->hMemory, + FILE_MAP_ALL_ACCESS, + 0, + 0, + i_wSize + ); + + if (NULL == l_pBuffer) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + *o_pHandle = (CShared::hShared)l_pShared; + + __try + { + memcpy(l_pBuffer, i_pData, i_wSize); + } + + __except ( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (l_pBuffer) + { + UnmapViewOfFile(l_pBuffer); + l_pBuffer = NULL; + } + + if (l_bRelease) + { + ReleaseMutex(l_pShared->hMutex); + } + + if (FALSE == l_bReturn) + { + Close((hShared)l_pShared); + l_pShared = NULL; + + if (o_pHandle) + { + *o_pHandle = NULL; + } + } + + return l_bReturn; + }//Shared_Create + + + //////////////////////////////////////////////////////////////////////////// + //Read + static tBOOL Read(const tXCHAR *i_pName, + tUINT8 *o_pData, + tUINT16 i_wSize + ) + { + HANDLE l_hMemory = NULL; + tBOOL l_bReturn = TRUE; + DWORD l_dwLen = 0; + wchar_t *l_pName = NULL; + tUINT8 *l_pBuffer = NULL; + + if ( (NULL == i_pName) + || (NULL == o_pData) + || (0 >= i_wSize) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_dwLen = (DWORD)wcslen(i_pName) + 128; + l_pName = (wchar_t*)malloc(sizeof(wchar_t) * l_dwLen); + + if (NULL == l_pName) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////// + //open shared memory object + Create_Name(l_pName, l_dwLen, ETYPE_FILE, i_pName); + + l_hMemory = OpenFileMappingW(FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + l_pName // name of mapping object + ); + + if (NULL == l_hMemory) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_pBuffer = (tUINT8*)MapViewOfFile(l_hMemory, + FILE_MAP_READ, + 0, + 0, + i_wSize + ); + + if (NULL == l_pBuffer) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + __try + { + memcpy(o_pData, l_pBuffer, i_wSize); + } + + __except ( (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR) + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (l_pBuffer) + { + UnmapViewOfFile(l_pBuffer); + l_pBuffer = NULL; + } + + if (l_hMemory) + { + CloseHandle(l_hMemory); + l_hMemory = NULL; + } + + return l_bReturn; + }//Read + + + + //////////////////////////////////////////////////////////////////////////// + //Write + static tBOOL Write(const tXCHAR *i_pName, + const tUINT8 *i_pData, + tUINT16 i_wSize + ) + { + HANDLE l_hMemory = NULL; + tBOOL l_bReturn = TRUE; + DWORD l_dwLen = 0; + wchar_t *l_pName = NULL; + tUINT8 *l_pBuffer = NULL; + + if ( (NULL == i_pName) + || (NULL == i_pData) + || (0 >= i_wSize) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_dwLen = (DWORD)wcslen(i_pName) + 128; + l_pName = (wchar_t*)malloc(sizeof(wchar_t) * l_dwLen); + + if (NULL == l_pName) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////// + //open shared memory object + Create_Name(l_pName, l_dwLen, ETYPE_FILE, i_pName); + + l_hMemory = OpenFileMappingW(FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + l_pName // name of mapping object + ); + + if (NULL == l_hMemory) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_pBuffer = (tUINT8*)MapViewOfFile(l_hMemory, + FILE_MAP_WRITE, + 0, + 0, + i_wSize + ); + + if (NULL == l_pBuffer) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + __try + { + memcpy(l_pBuffer, i_pData, i_wSize); + } + + __except ( (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR) + ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (l_pBuffer) + { + UnmapViewOfFile(l_pBuffer); + l_pBuffer = NULL; + } + + if (l_hMemory) + { + CloseHandle(l_hMemory); + l_hMemory = NULL; + } + + return l_bReturn; + }//Write + + + //////////////////////////////////////////////////////////////////////////// + //Lock + static eLock Lock(const tXCHAR *i_pName, CShared::hSem &o_rSem, tUINT32 i_dwTimeout_ms) + { + HANDLE l_hMutex = NULL; + eLock l_eReturn = CShared::E_OK; + DWORD l_dwLen = 0; + wchar_t *l_pName = NULL; + + o_rSem = SHARED_SEM_NULL; + + if (NULL == i_pName) + { + l_eReturn = CShared::E_ERROR; + goto l_lblExit; + } + + l_dwLen = (DWORD)wcslen(i_pName) + 128; + l_pName = (wchar_t*)malloc(sizeof(wchar_t) * l_dwLen); + + if (NULL == l_pName) + { + l_eReturn = CShared::E_ERROR; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////// + //open mutex and own it + Create_Name(l_pName, l_dwLen, ETYPE_MUTEX, i_pName); + + l_hMutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, l_pName); + if (NULL == l_hMutex) + { + l_eReturn = CShared::E_NOT_EXISTS; + goto l_lblExit; + } + + if (WAIT_OBJECT_0 != WaitForSingleObject(l_hMutex, i_dwTimeout_ms)) + { + l_eReturn = CShared::E_TIMEOUT; + goto l_lblExit; + } + + l_lblExit: + if (l_pName) + { + free(l_pName); + l_pName = NULL; + } + + if (SHARED_SEM_NULL != l_hMutex) + { + if (CShared::E_OK == l_eReturn) + { + o_rSem = l_hMutex; + } + else + { + CloseHandle(l_hMutex); + l_hMutex = SHARED_SEM_NULL; + } + } + + return l_eReturn; + }//Lock + + + //////////////////////////////////////////////////////////////////////////// + //UnLock + static eLock UnLock(CShared::hSem &io_rSem) + { + HANDLE l_hMutex = NULL; + eLock l_eReturn = CShared::E_ERROR; + + if (SHARED_SEM_NULL == io_rSem) + { + l_eReturn = CShared::E_NOT_EXISTS; + goto l_lblExit; + } + + ReleaseMutex(io_rSem); + + l_lblExit: + if (io_rSem) + { + CloseHandle(io_rSem); + io_rSem = SHARED_SEM_NULL; + } + + return l_eReturn; + }//UnLock + + + //////////////////////////////////////////////////////////////////////////// + //GetSemName + static const tXCHAR* GetName(hShared i_pShared) + { + if (NULL == i_pShared) + { + return FALSE; + } + + return i_pShared->pName; + } + + //////////////////////////////////////////////////////////////////////////// + //Close + static tBOOL Close(hShared i_hShared) + { + if (NULL == i_hShared) + { + return FALSE; + } + + //if (i_hShared->hMutex) + //{ + // WaitForSingleObject(i_hShared->hMutex, 3000); + //} + + if (i_hShared->hMemory) + { + CloseHandle(i_hShared->hMemory); + i_hShared->hMemory = NULL; + } + + if (i_hShared->hMutex) + { + CloseHandle(i_hShared->hMutex); + i_hShared->hMutex = NULL; + } + + if (i_hShared->pName) + { + PStrFreeDub(i_hShared->pName); + i_hShared->pName = NULL; + } + + delete i_hShared; + + return TRUE; + }//Shared_Close + + //////////////////////////////////////////////////////////////////////////// + //UnLink - linux required it due to fact that life time of shared object is + //almost infinit, and cleanup should be done manually + static tBOOL UnLink(const tXCHAR *i_pName) + { + UNUSED_ARG(i_pName); + return TRUE; + }//UnLink + + +private: + //////////////////////////////////////////////////////////////////////////// + //Create_Name + static tBOOL Create_Name(tXCHAR *o_pName, + size_t i_szName, + eType i_eType, + const tXCHAR *i_pPostfix + ) + { + if ( (NULL == o_pName) + || (16 >= i_szName) + || (ETYPE_MAX <= i_eType) + || (NULL == i_pPostfix) + ) + { + return FALSE; + } + + FILETIME l_tProcess_Time = {0}; + FILETIME l_tStub_01 = {0}; + FILETIME l_tStub_02 = {0}; + FILETIME l_tStub_03 = {0}; + + GetProcessTimes(GetCurrentProcess(), + &l_tProcess_Time, + &l_tStub_01, + &l_tStub_02, + &l_tStub_03 + ); + + if (ETYPE_MUTEX == i_eType) + { + swprintf_s(o_pName, + i_szName, + L"Local\\m%d%d%d%s", + GetCurrentProcessId(), + l_tProcess_Time.dwHighDateTime, + l_tProcess_Time.dwLowDateTime, + i_pPostfix + ); + } + else if (ETYPE_FILE == i_eType) + { + swprintf_s(o_pName, + i_szName, + L"Local\\f%d%d%d%s", + GetCurrentProcessId(), + l_tProcess_Time.dwHighDateTime, + l_tProcess_Time.dwLowDateTime, + i_pPostfix + ); + } + + return TRUE; + }//Create_Name +}; + + + + + + + + diff --git a/p7lib/Shared/Platforms/Windows_x86/PSharedLib.h b/p7lib/Shared/Platforms/Windows_x86/PSharedLib.h new file mode 100644 index 0000000..b7339c6 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PSharedLib.h @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef IPSHARED_LIB_H +#define IPSHARED_LIB_H + +#include "GTypes.h" + +#include "Length.h" +#include "PString.h" +#include "WString.h" +#include "SharedLib.h" +#include "PAtomic.h" + +class CPSharedLib + : public CSharedLib +{ +protected: + HMODULE m_pDll; + +public: + CPSharedLib(const tXCHAR *i_pPath) + : CSharedLib(i_pPath) + , m_pDll(NULL) + { + m_pDll = LoadLibraryW(i_pPath); + + if (m_pDll) + { + m_bState = TRUE; + } + } + + void *GetFunction(const tACHAR *i_pName) + { + return (void*)(GetProcAddress(m_pDll, i_pName)); + } + + virtual ~CPSharedLib() + { + if (m_pDll) + { + FreeLibrary(m_pDll); + m_pDll = NULL; + } + } +}; + +#endif //IPSHARED_LIB_H diff --git a/p7lib/Shared/Platforms/Windows_x86/PSignal.h b/p7lib/Shared/Platforms/Windows_x86/PSignal.h new file mode 100644 index 0000000..5e3d6f7 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PSignal.h @@ -0,0 +1,294 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus + +#ifndef PSIGNAL_H +#define PSIGNAL_H + +#include +#include +#include "signal.h" +#include "ISignal.h" + + +static stChContext g_stContext = {0}; + +//////////////////////////////////////////////////////////////////////////////// +//ChSignalHandler +static void __cdecl ChSignalHandler(int i_iSignal) +{ + if (g_stContext.iProcessed) + { + return; + } + + g_stContext.iProcessed ++; + + const char *l_pText = "unknown signal"; + + if (SIGABRT == i_iSignal) + { + l_pText = "SIGABRT"; + } + else if (SIGFPE == i_iSignal) + { + l_pText = "SIGFPE"; + } + else if (SIGILL == i_iSignal) + { + l_pText = "SIGILL"; + } + else if (SIGINT == i_iSignal) + { + l_pText = "SIGINT"; + } + else if (SIGSEGV == i_iSignal) + { + l_pText = "SIGSEGV"; + } + else if (SIGTERM == i_iSignal) + { + l_pText = "SIGTERM"; + } + + + if (g_stContext.pUserHandler) + { + g_stContext.pUserHandler((eCrashCode)(eCrashSignal + i_iSignal), l_pText, g_stContext.pUserContext); + } + + exit(1); +}//ChSignalHandler + + +//////////////////////////////////////////////////////////////////////////////// +//ChUnhandledExceptionFilter +static LONG WINAPI ChUnhandledExceptionFilter(__in struct _EXCEPTION_POINTERS *i_pException) +{ + if (g_stContext.iProcessed) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + if ( (STATUS_ACCESS_VIOLATION == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_ARRAY_BOUNDS_EXCEEDED == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_DATATYPE_MISALIGNMENT == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_FLT_DIVIDE_BY_ZERO == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_FLT_STACK_CHECK == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_ILLEGAL_INSTRUCTION == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_INT_DIVIDE_BY_ZERO == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_NONCONTINUABLE_EXCEPTION == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_PRIV_INSTRUCTION == i_pException->ExceptionRecord->ExceptionCode) + || (EXCEPTION_STACK_OVERFLOW == i_pException->ExceptionRecord->ExceptionCode) + //|| ( == i_pException->ExceptionRecord.ExceptionCode) + ) + { + g_stContext.iProcessed ++; + + if (g_stContext.pUserHandler) + { + g_stContext.pUserHandler(eCrashException, i_pException, g_stContext.pUserContext); + } + + exit(1); + } + + return EXCEPTION_CONTINUE_SEARCH; +}//ChUnhandledExceptionFilter + + +//////////////////////////////////////////////////////////////////////////////// +//ChPurecallHandler +static void ChPurecallHandler(void) +{ + if (g_stContext.iProcessed) + { + return; + } + + g_stContext.iProcessed ++; + + if (g_stContext.pUserHandler) + { + g_stContext.pUserHandler(eCrashPureCall, "Pure call", g_stContext.pUserContext); + } + + exit(1); +}//ChPurecallHandler + + +//////////////////////////////////////////////////////////////////////////////// +//ChMemoryAllocationHandler +static int ChMemoryAllocationHandler(size_t i_szSize) +{ + if (g_stContext.iProcessed) + { + return 0; + } + + g_stContext.iProcessed ++; + + char l_pText[32]; + + sprintf_s(l_pText, "%lld", (tINT64)i_szSize); + + if (g_stContext.pUserHandler) + { + g_stContext.pUserHandler(eCrashMemAlloc, l_pText, g_stContext.pUserContext); + } + + exit(1); + + return 0; +}//ChMemoryAllocationHandler + + +//////////////////////////////////////////////////////////////////////////////// +//ChInvalidParameterHandler +static void ChInvalidParameterHandler(const wchar_t* i_pExpression, + const wchar_t* i_pFunction, + const wchar_t* i_pFile, + unsigned int i_dwLine, + uintptr_t i_pReserved + ) +{ + if (g_stContext.iProcessed) + { + return; + } + + g_stContext.iProcessed ++; + + char l_pText[148]; + const wchar_t *l_pFunction = i_pFunction ? i_pFunction : L"Func:Unk"; + const wchar_t *l_pFile = i_pFile ? i_pFile : L"File:Unk"; + size_t l_szFile = i_pFile ? wcslen(i_pFile) : 0; + size_t l_szFunc = i_pFunction ? wcslen(i_pFunction) : 0; + + if ( l_szFile > 64 ) + { + l_szFile -= 64; + } + + if ( l_szFunc > 64 ) + { + l_szFunc -= 64; + } + + sprintf_s(l_pText, "{%S}{%S}{%d}", l_pFunction + l_szFunc, l_pFile + l_szFile, (int)i_dwLine); + + if (g_stContext.pUserHandler) + { + g_stContext.pUserHandler(eCrashInvalidParameter, l_pText, g_stContext.pUserContext); + } + + exit(1); +}//ChInvalidParameterHandler + + +//////////////////////////////////////////////////////////////////////////////// +//ChInstallPrivate +static tBOOL ChInstallPrivate() +{ + //////////////////////////////////////////////////////////////////////////// + //initialize handlers for all possible cases + signal(SIGABRT, ChSignalHandler); + signal(SIGFPE, ChSignalHandler); + signal(SIGILL, ChSignalHandler); + signal(SIGINT, ChSignalHandler); + signal(SIGSEGV, ChSignalHandler); + signal(SIGTERM, ChSignalHandler); + + //SetUnhandledExceptionFilter(ChUnhandledExceptionFilter); + AddVectoredExceptionHandler(1, ChUnhandledExceptionFilter); + + _set_purecall_handler(ChPurecallHandler); + + _set_new_mode(1); + _set_new_handler(ChMemoryAllocationHandler); + + _set_invalid_parameter_handler(ChInvalidParameterHandler); + + _CrtSetReportMode(_CRT_ERROR, 0); + _CrtSetReportMode(_CRT_ASSERT, 0); + + return TRUE; +}//ChInstallPrivate + + +//////////////////////////////////////////////////////////////////////////////// +//ChInstall +static tBOOL ChInstall() +{ + if (g_stContext.iInstalled) + { + return FALSE; + } + + + //////////////////////////////////////////////////////////////////////////// + //initialize parameters + memset(&g_stContext, 0, sizeof(g_stContext)); + g_stContext.iInstalled = 1; + g_stContext.iProcessed = 0; + + ChInstallPrivate(); + + return TRUE; +}//ChInstall + + +//////////////////////////////////////////////////////////////////////////////// +//ChSetHandler +static tBOOL ChSetHandler(fnCrashHandler i_fnHandler) +{ + if (!g_stContext.iInstalled) + { + return FALSE; + } + + g_stContext.pUserHandler = i_fnHandler; + + return TRUE; +}//ChSetHandler + + +//////////////////////////////////////////////////////////////////////////////// +//ChSetContext +static tBOOL ChSetContext(void *i_pContext) +{ + if (!g_stContext.iInstalled) + { + return FALSE; + } + + g_stContext.pUserContext = i_pContext; + + return TRUE; +}//ChSetContext + + +//////////////////////////////////////////////////////////////////////////////// +//ChUnInstall +static tBOOL ChUnInstall() +{ + return TRUE; +}//ChUnInstall + +#endif //PSIGNAL_H \ No newline at end of file diff --git a/p7lib/Shared/Platforms/Windows_x86/PSocket.h b/p7lib/Shared/Platforms/Windows_x86/PSocket.h new file mode 100644 index 0000000..6c8d050 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PSocket.h @@ -0,0 +1,220 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include +#include +#include +#include "GTypes.h" +#include "AList.h" + +//256k +#define CLIENT_RECV_BUFFER_SIZE (0x40000) +//2m +#define CLIENT_SEND_BUFFER_SIZE (0x200000) + +//2m +#define SERVER_RECV_BUFFER_SIZE (0x200000) +//256k +#define SERVER_SEND_BUFFER_SIZE (0x40000) + + +typedef SOCKET tSOCKET; + +typedef int tADDR_LEN; + +typedef addrinfoW tADDR_INFO; + +#define INVALID_SOCKET_VAL (INVALID_SOCKET) +#define CONNECTION_IN_PROGRESS (WSAEWOULDBLOCK) + +#define CLOSE_SOCKET(i_Socket) closesocket(m_hSocket) + + +#define GET_SOCKET_ERROR() WSAGetLastError() + +//#define SOCKET_ERROR (-1) + +#define GET_ADDR_INFO(i_Node, i_Service, i_Hints, o_Res) GetAddrInfoW(i_Node,\ + i_Service,\ + i_Hints,\ + o_Res) + +#define FREE_ADDR_INFO(i_Info) FreeAddrInfoW(i_Info) + + +//////////////////////////////////////////////////////////////////////////////// +//WSA_Init +static inline tBOOL WSA_Init() +{ + WSADATA l_tWSA; + + if (0 != WSAStartup(MAKEWORD(1,1), &l_tWSA)) + { + return FALSE; + } + return TRUE; +}//WSA_Init + + +//////////////////////////////////////////////////////////////////////////////// +//WSA_UnInit +static inline void WSA_UnInit() +{ + WSACleanup(); +}//WSA_UnInit + + +//////////////////////////////////////////////////////////////////////////////// +//Print_SAddr +static tBOOL Print_SAddr(sockaddr *i_pAddress, XCHAR *o_pIP, tUINT32 i_dwLen) +{ + tBOOL l_bReturn = FALSE; + tUINT32 l_dwSize = 0; + + if (NULL == i_pAddress) + { + return l_bReturn; + } + + if (AF_INET6 == i_pAddress->sa_family) + { + l_dwSize = sizeof(sockaddr_in6); + } + else if (AF_INET == i_pAddress->sa_family) + { + l_dwSize = sizeof(sockaddr_in); + } + + if (0 == WSAAddressToStringW(i_pAddress, + l_dwSize, + NULL, + o_pIP, + (LPDWORD)&i_dwLen + ) + ) + { + l_bReturn = TRUE; + } + + return l_bReturn; +}//Print_SAddr + + +//////////////////////////////////////////////////////////////////////////////// +//PEnumIpsHlp +static tBOOL PEnumIpsHlp(const char *i_pHost, CBList *io_pList) +{ + char l_pPort[16]= TOSTR(9009); + addrinfo *l_pInfo = NULL; + addrinfo *l_pNext = NULL; + addrinfo l_tHint = {0}; + + l_tHint.ai_family = AF_UNSPEC; + l_tHint.ai_socktype = SOCK_DGRAM; + l_tHint.ai_protocol = IPPROTO_UDP; + + //http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx + if (0 == getaddrinfo(i_pHost, l_pPort, &l_tHint, &l_pInfo)) + { + for(l_pNext = l_pInfo; l_pNext != NULL; l_pNext = l_pNext->ai_next) + { + if ( ( (AF_INET == l_pNext->ai_family) + || (AF_INET6 == l_pNext->ai_family) + ) + && (SOCK_DGRAM == l_pNext->ai_socktype) + && (IPPROTO_UDP == l_pNext->ai_protocol) + ) + { + sockaddr_storage *l_pNew = new sockaddr_storage; + if (AF_INET == l_pNext->ai_family) + { + memcpy(l_pNew, l_pNext->ai_addr, sizeof(sockaddr_in)); + } + else if (AF_INET6 == l_pNext->ai_family) + { + memcpy(l_pNew, l_pNext->ai_addr, sizeof(sockaddr_in6)); + } + else + { + memset(l_pNew, 0, sizeof(sockaddr_storage)); + } + + io_pList->Add_After(NULL, l_pNew); + } + } + + freeaddrinfo(l_pInfo); + } + else + { + return FALSE; + } + + return TRUE; +}//PEnumIpsHlp + + +//////////////////////////////////////////////////////////////////////////////// +//PEnumIps +static tBOOL PEnumIps(CBList *io_pList) +{ + if (!io_pList) + { + return FALSE; + } + + io_pList->Clear(TRUE); + + const size_t l_szHost = 256; + char l_pHost[l_szHost]; + + if (0 == gethostname(l_pHost, l_szHost)) + { + PEnumIpsHlp(l_pHost, io_pList); + } + + PEnumIpsHlp("127.0.0.1", io_pList); + PEnumIpsHlp("::1", io_pList); + + return TRUE; +}//PEnumIps + + +//////////////////////////////////////////////////////////////////////////////// +//Disable_PortUnreachable_ICMP +static tBOOL Disable_PortUnreachable_ICMP(tSOCKET i_hSocket) +{ + tUINT32 l_dwBytesReturned = 0; + tBOOL l_bNewBehavior = FALSE; + tINT32 l_iStatus = 0; + + + l_iStatus = WSAIoctl(i_hSocket, + SIO_UDP_CONNRESET, + &l_bNewBehavior, + sizeof(l_bNewBehavior), + NULL, + 0, + (LPDWORD)&l_dwBytesReturned, + NULL, + NULL + ); + return (SOCKET_ERROR == l_iStatus) ? FALSE : TRUE; +}//Disable_PortUnreachable_ICMP diff --git a/p7lib/Shared/Platforms/Windows_x86/PString.h b/p7lib/Shared/Platforms/Windows_x86/PString.h new file mode 100644 index 0000000..ac6b8e3 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PString.h @@ -0,0 +1,232 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include + +#define PRINTF(...) wprintf(__VA_ARGS__) + +/////////////////////////////////////////////////////////////////////////////// +//PStrLen +static inline tUINT32 PStrLen(const tXCHAR *i_pText) +{ + return (tUINT32)wcslen(i_pText); +}//PStrLen + +/////////////////////////////////////////////////////////////////////////////// +//PUStrLen +static inline tUINT32 PUStrLen(const tXCHAR *i_pText) +{ + return (tUINT32)wcslen(i_pText); +}//PUStrLen + + +//////////////////////////////////////////////////////////////////////////////// +//PStrCpy +static inline tXCHAR* PStrCpy(tXCHAR *i_pDst, + size_t i_szDst, + const tXCHAR *i_pSrc + ) +{ + wcscpy_s((wchar_t*)i_pDst, i_szDst, (wchar_t*)i_pSrc); + return i_pDst; +}//PStrLen + + +//////////////////////////////////////////////////////////////////////////////// +//PWStrCpy +static inline tXCHAR* PWStrCpy(tWCHAR *i_pDst, + size_t i_szDst, + const tWCHAR *i_pSrc + ) +{ + wcscpy_s((wchar_t*)i_pDst, i_szDst, (wchar_t*)i_pSrc); + return i_pDst; +}//PWStrCpy + + +//////////////////////////////////////////////////////////////////////////////// +//PStrCpy +static inline tXCHAR* PStrNCpy(tXCHAR *i_pDst, + size_t i_szDst, + const tXCHAR *i_pSrc, + size_t i_pSrcMaxCount + ) +{ + wcsncpy_s((wchar_t*)i_pDst, i_szDst, (wchar_t*)i_pSrc, i_pSrcMaxCount); + return i_pDst; +}//PStrLen + + +/////////////////////////////////////////////////////////////////////////////// +//PStrNCmp +static inline tINT32 PStrNCmp(const tXCHAR *i_pS1, const tXCHAR *i_pS2, size_t i_szLen) +{ + return wcsncmp(i_pS1, i_pS2, i_szLen); +}//PStrNCmp + + +//////////////////////////////////////////////////////////////////////////////// +//PStrNCmp +static inline tINT32 PStrNiCmp(const tXCHAR *i_pS1, + const tXCHAR *i_pS2, + size_t i_szLen + ) +{ + return _wcsnicmp(i_pS1, i_pS2, i_szLen); +}//PStrNCmp + + +//////////////////////////////////////////////////////////////////////////////// +//PStrNCmp +static inline tINT32 PStrICmp(const tXCHAR *i_pS1, const tXCHAR *i_pS2) +{ + return _wcsicmp(i_pS1, i_pS2); +}//PStrNCmp + + +//////////////////////////////////////////////////////////////////////////////// +//PStrCmp +static inline tINT32 PStrCmp(const tXCHAR *i_pS1, const tXCHAR *i_pS2) +{ + return wcscmp(i_pS1, i_pS2); +}//PStrCmp + + +/////////////////////////////////////////////////////////////////////////////// +//PStrToInt +static inline tINT32 PStrToInt(const tXCHAR *i_pS1) +{ + return _wtoi(i_pS1); +}//PStrToInt + + +/////////////////////////////////////////////////////////////////////////////// +//PStrCpy +static inline void PUStrCpy(tWCHAR *i_pDst, tUINT32 i_dwMax_Len, const tXCHAR *i_pSrc) +{ + wcscpy_s((wchar_t *)i_pDst, i_dwMax_Len, i_pSrc); +}//PStrCpy + + +/////////////////////////////////////////////////////////////////////////////// +//PSPrint +static inline tINT32 PSPrint(tXCHAR *o_pBuffer, + size_t i_szBuffer, + const tXCHAR *i_pFormat, + ... + ) +{ + va_list l_pVA; + int l_iReturn = 0; + + va_start(l_pVA, i_pFormat); + l_iReturn = _vsnwprintf_s(o_pBuffer, i_szBuffer, _TRUNCATE, i_pFormat, l_pVA); + va_end(l_pVA); + + return (tINT32)l_iReturn; +}//PSPrint + + +/////////////////////////////////////////////////////////////////////////////// +//PSPrint +static inline tINT32 PSPrint(tACHAR *o_pBuffer, + size_t i_szBuffer, + const tACHAR *i_pFormat, + ... + ) +{ + va_list l_pVA; + int l_iReturn = 0; + + va_start(l_pVA, i_pFormat); + l_iReturn = _vsnprintf_s(o_pBuffer, i_szBuffer, _TRUNCATE, i_pFormat, l_pVA); + va_end(l_pVA); + + return (tINT32)l_iReturn; +}//PSPrint + + +/////////////////////////////////////////////////////////////////////////////// +//PVsnprintf +static inline int PVsnprintf(tXCHAR *o_pBuffer, size_t i_szBuffer, const tXCHAR *i_pFormat, va_list i_pArgs) +{ + //size_t l_szRem = 0; + //StringCbVPrintfExW(o_pBuffer, + // i_szBuffer, + // NULL, + // &l_szRem, + // STRSAFE_IGNORE_NULLS, + // i_pFormat, + // i_pArgs + // ); + //return (int)i_szBuffer - (int)l_szRem; + return _vsnwprintf_s(o_pBuffer, i_szBuffer, _TRUNCATE, i_pFormat, i_pArgs); +}//PVsnprintf + + +/////////////////////////////////////////////////////////////////////////////// +//PStrDub +static inline tXCHAR *PStrDub(const tXCHAR *i_pStr) +{ + return _wcsdup(i_pStr); +}//PStrDub + + +/////////////////////////////////////////////////////////////////////////////// +//PStrFreeDub +static inline void PStrFreeDub(tXCHAR *i_pStr) +{ + free(i_pStr); +}//PStrFreeDub + + +/////////////////////////////////////////////////////////////////////////////// +//PStrChr +static inline const tXCHAR *PStrChr(const tXCHAR * i_pStr, tXCHAR i_cCh) +{ + return wcschr(i_pStr, i_cCh); +}//PStrChr + +/////////////////////////////////////////////////////////////////////////////// +//PStrChr +static inline tXCHAR *PStrChr(tXCHAR * i_pStr, tXCHAR i_cCh) +{ + return wcschr(i_pStr, i_cCh); +}//PStrChr + + +/////////////////////////////////////////////////////////////////////////////// +//PStrrChr +static inline tXCHAR *PStrrChr(tXCHAR * i_pStr, tXCHAR i_cCh) +{ + return wcsrchr(i_pStr, i_cCh); +}//PStrrChr + +/////////////////////////////////////////////////////////////////////////////// +//PStrrChr +static inline const tXCHAR *PStrrChr(const tXCHAR * i_pStr, const tXCHAR i_cCh) +{ + return wcsrchr(i_pStr, i_cCh); +}//PStrrChr + + +/////////////////////////////////////////////////////////////////////////////// +//PStrScan +#define PStrScan(i_pBuffer, i_pFormat, ...) swscanf_s(i_pBuffer, i_pFormat, __VA_ARGS__) diff --git a/p7lib/Shared/Platforms/Windows_x86/PSystem.h b/p7lib/Shared/Platforms/Windows_x86/PSystem.h new file mode 100644 index 0000000..c5ce255 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PSystem.h @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PSYSTEM_H +#define PSYSTEM_H + +class CSys +{ +public: + /////////////////////////////////////////////////////////////////////////////// + //Get_Host_Name + static tBOOL Get_Host_Name(tWCHAR *o_pName, size_t i_szName) + { + if ( (NULL == o_pName) + || (32 >= i_szName) + ) + { + return FALSE; + } + + DWORD l_dwMax_Len = (DWORD)i_szName; + return GetComputerNameW((wchar_t*)o_pName, &l_dwMax_Len); + }//Get_Host_Name + + + /////////////////////////////////////////////////////////////////////////////// + //Get_Host_Name + static tBOOL Get_Host_Name(tACHAR *o_pName, size_t i_szName) + { + const size_t l_szName = 256; + DWORD l_dwSize = (DWORD)l_szName; + wchar_t l_pName[l_szName]; + + if (GetComputerNameW((wchar_t*)l_pName, &l_dwSize)) + { + Convert_UTF16_To_UTF8(l_pName, o_pName, (tUINT32)i_szName); + } + else + { + strcpy_s(o_pName, i_szName, "Unknown:Error"); + } + return TRUE; + }//Get_Host_Name + + + + /////////////////////////////////////////////////////////////////////////////// + //Get_DateTime + static tBOOL Get_DateTime(tUINT32 &o_rYear, + tUINT32 &o_rMonth, + tUINT32 &o_rDay, + tUINT32 &o_rHour, + tUINT32 &o_rMinute, + tUINT32 &o_rSecond, + tUINT32 &o_rmSec + ) + { + SYSTEMTIME l_sTitem = {0}; + GetLocalTime(&l_sTitem); + + o_rYear = (tUINT32)l_sTitem.wYear; + o_rMonth = (tUINT32)l_sTitem.wMonth; + o_rDay = (tUINT32)l_sTitem.wDay; + o_rHour = (tUINT32)l_sTitem.wHour; + o_rMinute = (tUINT32)l_sTitem.wMinute; + o_rSecond = (tUINT32)l_sTitem.wSecond; + o_rmSec = (tUINT32)l_sTitem.wMilliseconds; + + return TRUE; + }//Get_Host_Name + +}; + + +#endif //PSYSTEM_H diff --git a/p7lib/Shared/Platforms/Windows_x86/PThreadShell.h b/p7lib/Shared/Platforms/Windows_x86/PThreadShell.h new file mode 100644 index 0000000..5033204 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PThreadShell.h @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include + +#define THSHELL_CALL_TYPE __stdcall +#define THSHELL_RET_TYPE tUINT32 + +#define THSHELL_RET_OK 0 +#define THSHELL_RET_NOK 1 + + +//////////////////////////////////////////////////////////////////////////////// +class CThShell +{ +public: + //////////////////////////////////////////////////////////////////////////// + //Base types + typedef HANDLE tTHREAD; + typedef THSHELL_RET_TYPE (THSHELL_CALL_TYPE *tpThreadProc)(void *i_pParameter); + + + //////////////////////////////////////////////////////////////////////////// + //Create + static tBOOL Create(tpThreadProc i_pThread_Proc, + void *i_pPrm, + tTHREAD *o_pThread, + const tXCHAR *i_pName + ) + { + if ( ( NULL == i_pThread_Proc ) + || ( NULL == o_pThread ) + ) + { + return FALSE; + } + + *o_pThread = (tTHREAD)_beginthreadex( NULL, + 0, + i_pThread_Proc, + i_pPrm, + 0, + NULL + ); + + //SetThreadName( *pThread_id, thread_name); + + return (*o_pThread) ? TRUE : FALSE; + }//Create + + + //////////////////////////////////////////////////////////////////////////// + //Cleanup + static void Cleanup() + { + _endthreadex( 0 ); + }//Thread_Cleanup + + + //////////////////////////////////////////////////////////////////////////// + //Close + static tBOOL Close(tTHREAD i_hThread, tUINT32 i_dwTimeOut) + { + if (NULL == i_hThread) + { + return TRUE; + } + + if ( WAIT_OBJECT_0 == WaitForSingleObject( i_hThread, i_dwTimeOut ) ) + { + CloseHandle(i_hThread); + return TRUE; + } + + return FALSE; + }//Close + + + //////////////////////////////////////////////////////////////////////////// + //Sleep + static void Sleep(tUINT32 i_dwTimeOut) + { + ::Sleep(i_dwTimeOut); + }//Sleep +}; + diff --git a/p7lib/Shared/Platforms/Windows_x86/PTime.h b/p7lib/Shared/Platforms/Windows_x86/PTime.h new file mode 100644 index 0000000..d9a8811 --- /dev/null +++ b/p7lib/Shared/Platforms/Windows_x86/PTime.h @@ -0,0 +1,204 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#define TIME_HRS_100NS 36000000000ull +#define TIME_MIN_100NS 600000000ull +#define TIME_SEC_100NS 10000000ull +#define TIME_MSC_100NS 10000ull + +//////////////////////////////////////////////////////////////////////////////// +//GetTickCount - exist in OS +//tUINT32 GetTickCount() +//{ +//}//GetTickCount + + +//////////////////////////////////////////////////////////////////////////////// +//GetPerformanceCounter +static inline tUINT64 GetPerformanceCounter() +{ + LARGE_INTEGER l_qwValue; + l_qwValue.QuadPart = 0; + QueryPerformanceCounter(&l_qwValue); + return l_qwValue.QuadPart; +}//GetPerformanceCounter + + +//////////////////////////////////////////////////////////////////////////////// +//GetPerformanceFrequency +static inline tUINT64 GetPerformanceFrequency() +{ + LARGE_INTEGER l_qwValue; + l_qwValue.QuadPart = 0; + QueryPerformanceFrequency(&l_qwValue); + return l_qwValue.QuadPart; +}//GetPerformanceFrequency + + +//////////////////////////////////////////////////////////////////////////////// +//GetEpochTime +//return a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC). +static inline void GetEpochTime(tUINT32 *o_pHi, tUINT32 *o_pLow) +{ + SYSTEMTIME l_sSTime = {0}; + FILETIME l_sFTime = {0}; + GetSystemTime(&l_sSTime); + + SystemTimeToFileTime(&l_sSTime, &l_sFTime); + if (o_pHi) + { + *o_pHi = l_sFTime.dwHighDateTime; + } + + if (o_pLow) + { + *o_pLow = l_sFTime.dwLowDateTime; + } +}//GetEpochTime + + +//////////////////////////////////////////////////////////////////////////////// +//UnpackLocalTime +//convert a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC) +//to readable form +static inline void UnpackLocalTime(tUINT64 i_qwTime, + tUINT32 &o_rYear, + tUINT32 &o_rMonth, + tUINT32 &o_rDay, + tUINT32 &o_rHour, + tUINT32 &o_rMinutes, + tUINT32 &o_rSeconds, + tUINT32 &o_rMilliseconds, + tUINT32 &o_rMicroseconds, + tUINT32 &o_rNanoseconds + ) +{ + tUINT32 l_dwReminder = i_qwTime % TIME_MSC_100NS; //micro & 100xNanoseconds + tUINT32 l_dwNano = i_qwTime % 10; + tUINT32 l_dwMicro = l_dwReminder / 10; + + i_qwTime -= l_dwReminder; + + SYSTEMTIME l_sTime = {0}; + FILETIME l_sLocalTime = {0}; + + FileTimeToLocalFileTime((FILETIME*)&i_qwTime, &l_sLocalTime); + FileTimeToSystemTime(&l_sLocalTime, &l_sTime); + + o_rYear = l_sTime.wYear; + o_rMonth = l_sTime.wMonth; + o_rDay = l_sTime.wDay; + o_rHour = l_sTime.wHour; + o_rMinutes = l_sTime.wMinute; + o_rSeconds = l_sTime.wSecond; + o_rMilliseconds = l_sTime.wMilliseconds; + o_rMicroseconds = l_dwMicro; + o_rNanoseconds = l_dwNano; +}//UnpackLocalTime + + +//////////////////////////////////////////////////////////////////////////////// +//PackLocalTime +//convert date & time to 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC) +tUINT64 static inline PackLocalTime(tUINT32 i_uiYear, + tUINT32 i_uiMonth, + tUINT32 i_uiDay, + tUINT32 i_uiHour, + tUINT32 i_uiMinutes, + tUINT32 i_uiSeconds, + tUINT32 i_uiMilliseconds, + tUINT32 i_uiMicroseconds, + tUINT32 i_uiNanoseconds + ) +{ + FILETIME l_sLocal = {0}; + FILETIME l_sSystem = {0}; + SYSTEMTIME l_sTime = {0}; + + l_sTime.wYear = (WORD)i_uiYear; + l_sTime.wMonth = (WORD)i_uiMonth; + l_sTime.wDay = (WORD)i_uiDay; + l_sTime.wHour = (WORD)i_uiHour; + l_sTime.wMinute = (WORD)i_uiMinutes; + l_sTime.wSecond = (WORD)i_uiSeconds; + l_sTime.wMilliseconds = (WORD)i_uiMilliseconds; + + SystemTimeToFileTime(&l_sTime, &l_sLocal); + LocalFileTimeToFileTime(&l_sLocal, &l_sSystem); + + tUINT64 l_qwReturn = ((tUINT64)(l_sSystem.dwHighDateTime) << 32) + (tUINT64)(l_sSystem.dwLowDateTime); + + l_qwReturn += (i_uiMicroseconds * 10ull) + (i_uiNanoseconds / 100ull); + + return l_qwReturn; +}//PackLocalTime + + +//////////////////////////////////////////////////////////////////////////////// +//GetSecondOfDay +static inline tUINT32 GetSecondOfDay() +{ + SYSTEMTIME l_sTime = {0}; + + GetLocalTime(&l_sTime); + + return 3600 * (tUINT32)l_sTime.wHour + (tUINT32)l_sTime.wMinute * 60 + (tUINT32)l_sTime.wSecond; +}//GetSecondOfDay + + +//////////////////////////////////////////////////////////////////////////////// +//GetEpochTime +//return a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC). +static inline tUINT64 GetEpochTime() +{ + SYSTEMTIME l_sSTime = {0}; + FILETIME l_sFTime = {0}; + GetSystemTime(&l_sSTime); + + SystemTimeToFileTime(&l_sSTime, &l_sFTime); + + return (((tUINT64)l_sFTime.dwHighDateTime) << 32ull) + (tUINT64)l_sFTime.dwLowDateTime; +}//GetEpochTime + + +//////////////////////////////////////////////////////////////////////////////// +//GetEpochLocalTime +//return a 64-bit value of 100-nanosecond intervals since January 1, 1601 (UTC). +static inline tUINT64 GetEpochLocalTime() +{ + SYSTEMTIME l_sSTime = {0}; + FILETIME l_sFTime = {0}; + GetLocalTime(&l_sSTime); + + SystemTimeToFileTime(&l_sSTime, &l_sFTime); + + return (((tUINT64)l_sFTime.dwHighDateTime) << 32ull) + (tUINT64)l_sFTime.dwLowDateTime; +}//GetEpochTime + + +//////////////////////////////////////////////////////////////////////////////// +//GetUtcOffsetSeconds +//return UTC0 offset in seconds +static inline tINT32 GetUtcOffsetSeconds() +{ + TIME_ZONE_INFORMATION l_sTZ = {}; + GetTimeZoneInformation(&l_sTZ); + return (tINT32)l_sTZ.Bias * -60; +} \ No newline at end of file diff --git a/p7lib/Shared/Predicate.h b/p7lib/Shared/Predicate.h new file mode 100644 index 0000000..87bc659 --- /dev/null +++ b/p7lib/Shared/Predicate.h @@ -0,0 +1,421 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +#define PR_USE_REGEXP + +#if defined(PR_USE_REGEXP) + #pragma warning(disable : 4995 ) + #include + #include +#endif + + +//////////////////////////////////////////////////////////////////////////////// +enum ePr_VType +{ + EPR_VTYPE_UNK = -1, + EPR_VTYPE_INT = 0, + EPR_VTYPE_FLOAT , + EPR_VTYPE_DATE , + EPR_VTYPE_WTEXT , + EPR_VTYPE_ENUM //user enumes +1, +2, +3, ... etc +}; + + +//////////////////////////////////////////////////////////////////////////////// +enum ePr_Op +{ + EPR_OP_UNK = -1, // + EPR_OP_EQUAL = 0, //= + EPR_OP_NOT_EQUAL , //!= + EPR_OP_GREATER , //> + EPR_OP_GREATER_OR_EQUAL , //>= + EPR_OP_LESS , //< + EPR_OP_LESS_OR_EQUAL , //<= + EPR_OP_LEFT_INCLUDE , //<< + EPR_OP_RIGHT_INCLUDE , //>> + EPR_OP_LEFT_NOT_INCLUDE , // + +#if defined(PR_USE_REGEXP) + EPR_OP_REG_EXP , //r= + EPR_OP_WILD_CARD //w= +#endif +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_Op_Text +{ + const tXCHAR *pText; + tUINT32 dwLen; + ePr_Op eType; + ePr_Op eRevers; + tBOOL bDigit; +}; + +static const sPr_Op_Text g_pOperators[] = +{ + { TM("<="), 2, EPR_OP_LESS_OR_EQUAL, EPR_OP_GREATER_OR_EQUAL, TRUE }, + { TM("<<"), 2, EPR_OP_LEFT_INCLUDE, EPR_OP_RIGHT_INCLUDE, FALSE}, + { TM(">>"), 2, EPR_OP_RIGHT_INCLUDE, EPR_OP_LEFT_INCLUDE, FALSE}, + { TM(""), 2, EPR_OP_RIGHT_NOT_INCLUDE,EPR_OP_LEFT_NOT_INCLUDE, FALSE}, + { TM("!="), 2, EPR_OP_NOT_EQUAL, EPR_OP_NOT_EQUAL, TRUE }, + { TM(">="), 2, EPR_OP_GREATER_OR_EQUAL, EPR_OP_LESS_OR_EQUAL, TRUE }, + { TM("="), 1, EPR_OP_EQUAL, EPR_OP_EQUAL, TRUE }, + { TM(">"), 1, EPR_OP_GREATER, EPR_OP_LESS, TRUE }, + { TM("<"), 1, EPR_OP_LESS, EPR_OP_GREATER, TRUE }, + +#if defined(PR_USE_REGEXP) + { TM("r="), 2, EPR_OP_REG_EXP, EPR_OP_REG_EXP, FALSE}, + { TM("w="), 2, EPR_OP_WILD_CARD, EPR_OP_WILD_CARD, FALSE}, +#endif +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_Var +{ + tXCHAR *m_pName; + ePr_VType m_eType; + tUINT32 m_dwLength; //length of the text if it is + tBOOL m_bUsed; + + union + { + tXCHAR *m_pValue; + tUINT64 m_qwValue; + double m_dbValue; + }; + + sPr_Var(tXCHAR *i_pName, ePr_VType i_eType) + : m_pName(NULL) + , m_eType(i_eType) + , m_dwLength(0) + , m_bUsed(FALSE) + , m_qwValue(0) //the largest value in union + { + tUINT32 l_dwLen = (i_pName) ? PStrLen(i_pName) : 0; + + if (l_dwLen) + { + m_pName = new tXCHAR[l_dwLen + 1]; + if (m_pName) + { + PStrCpy(m_pName, l_dwLen + 1, i_pName); + } + } + } + + ~sPr_Var() + { + if (m_pName) + { + delete [] m_pName; + m_pName = NULL; + } + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_Enum_Item +{ + tXCHAR *m_pName; + int m_iValue; + + sPr_Enum_Item(tXCHAR *i_pName, int i_iValue) + : m_pName(NULL) + , m_iValue(i_iValue) + { + tUINT32 l_dwLen = (i_pName) ? PStrLen(i_pName) : 0; + + if (l_dwLen) + { + m_pName = new tXCHAR[l_dwLen + 1]; + if (m_pName) + { + PStrCpy(m_pName, l_dwLen + 1, i_pName); + } + } + } + + ~sPr_Enum_Item() + { + if (m_pName) + { + delete [] m_pName; + m_pName = NULL; + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_Enum +{ + tUINT32 m_dwID; + CBList m_cItems; + + sPr_Enum(tUINT32 i_dwID) : m_dwID(i_dwID) {} + ~sPr_Enum() + { + m_cItems.Clear(TRUE); + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_Group; + +struct sPr_Node +{ + union + { + sPr_Group *m_pGroup; + tXCHAR *m_pValue; + tUINT64 m_qwValue; + double m_dbValue; + }; + + tBOOL m_bLink; //if TRUE we use m_pGroup, otherwise - values + ePr_Op m_eOperator; + tUINT32 m_dwLength; //length of the text if it is + sPr_Var *m_pVariable; +#if defined(PR_USE_REGEXP) + QRegExp *m_pRE; +#endif + + sPr_Node(); + ~sPr_Node(); +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_OrGroup +{ + CBList m_cNodes; + + ~sPr_OrGroup() + { + m_cNodes.Clear(TRUE); + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sPr_Group +{ + CBList m_cOrGroups; + + ~sPr_Group() + { + m_cOrGroups.Clear(TRUE); + } +}; + + + +//////////////////////////////////////////////////////////////////////////////// +//Normal class usage +//1. Create child class with yours structure +//2. Implement abstract function Set_Data() +//3. Set variables list using Set_Variables() +//4. If you are using enums - use Set_Enum() +//5. Set predicate string - Set_Predicate() +//6. Use Compare() to compare you structure using predicate +// +//See usage example at the end of this header file +class CPredicate +{ +protected: + tXCHAR *m_pPr; + tUINT32 m_dwPr_Max; + tUINT32 m_dwPr_Len; + + CBList m_cVars; + CBList m_cEnums; + sPr_Group m_cGroup; + tXCHAR m_cError[512]; +public: + CPredicate(); + virtual ~CPredicate(); + + //////////////////////////////////////////////////////////////////////////// + //Predicate (i_pPr) consist of next part + //Variables - %MyVariable% + //Constants - "0x20" possible values Int, Float, Date, String, Enum. Date + // has simple format "DD.MM.YYYY HH:MM:SS.MS" + //Atoms - atom is working block, you compare variable and constant. It + // is not possible to compare 2 variables, only variable and + // constant, next operators are available: "<=", "<<", ">>", "", "!=", ">=", "=", ">", "<". Operators "<<", ">>" used + // only for text ("T1 << T2" - T1 contains T2) + //Grouping - "(" and ")" + //Operators - "&", "|" + //Examples: + //$Var1$ >="0x10" & "Text" >> $Var2$ + //$Var1$ >="500" & ("Text" >> $Var2$ | "Text1" >> $Var2$) + virtual tBOOL Set_Predicate(const tXCHAR *i_pPr); + tXCHAR *Get_Error(); + + + //////////////////////////////////////////////////////////////////////////// + //Set_Variables() + // i_dwCount - count of the variables, each variable has 2 values + // tXCHAR - name of the variable, allowed any characters + // ePr_VType - type of the variable + // ... - variables (2 value: name & type) + tBOOL Set_Variables(tUINT32 i_dwCount, ...); + + //////////////////////////////////////////////////////////////////////////// + //Set_Enum() + // i_dwEnum_ID - ID of the enum, EPR_VTYPE_ENUM, EPR_VTYPE_ENUM + 1, ... etc + // i_dwCount - count of the enum values. Each value has 2 fields + // tXCHAR - text value representation + // int - int value representation + // ... - enum values (2 fields: text & int) + tBOOL Set_Enum(tUINT32 i_dwEnum_ID, tUINT32 i_dwCount, ...); + + + tBOOL Check(const void *i_pData); +protected: + tBOOL Check(sPr_Group *i_pGroup); + + tBOOL Build(sPr_Group *i_pGroup, tUINT32 *io_pOffset); + tBOOL Add_Node(CBList *i_pNodes, tUINT32 *io_pOffset); + tBOOL Fill_Node(sPr_Node *i_pNode, + tXCHAR *i_pVariable, + tXCHAR *i_pConst + ); + + tBOOL Is_True(sPr_Node *i_pNode); + + tBOOL Is_Sub(tXCHAR *i_pString, + tUINT32 i_dwLenght, + tXCHAR *i_pSearch, + tUINT32 i_dwSub_Len + ); + + //re-implement this function, you should get yours input structure and + //every field put to the m_cVars list. + virtual tBOOL Fill_Variables(const void *i_pData) = 0; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// Predicate Example +//////////////////////////////////////////////////////////////////////////////// +// +// +// enum eTest1 +// { +// ETEST1_ENUM0 = 0, +// ETEST1_ENUM1 = 1, +// ETEST1_ENUM2 = 2, +// ETEST1_ENUM3 = 3 +// }; +// +// struct sTest1 +// { +// tUINT32 m_dwInt; +// eTest1 m_eEnum; +// tXCHAR *m_pText; +// }; +// +//////////////////////////////////////////////////////////////////////////////// +// class CMy_Pred: +// public CPredicate +// { +// public: +// CMy_Pred(): +// CPredicate() +// { +// Set_Variables(3, +// TM("Int"), EPR_VTYPE_INT, //Index = 0; +// TM("Enum"), EPR_VTYPE_ENUM + 0, //Index = 1; +// TM("Text"), EPR_VTYPE_WTEXT //Index = 2; +// ); +// +// Set_Enum(EPR_VTYPE_ENUM + 0, +// 4, +// TM("ENUM0"), 0, //ETEST1_ENUM0 = 0, +// TM("ENUM1"), 1, //ETEST1_ENUM1 = 1, +// TM("ENUM2"), 2, //ETEST1_ENUM2 = 2, +// TM("ENUM3"), 3 //ETEST1_ENUM3 = 3 +// ); +// } +// +// protected: +// BOOL Fill_Variables(void *i_pData) +// { +// sPr_Var *l_pVar = m_cVars[0];//Index = 0, first declared variable "Int" +// if (l_pVar->m_bUsed) +// { +// l_pVar->m_qwValue = ((sTest1*)i_pData)->m_dwInt; +// } +// +// l_pVar = m_cVars[1]; //Index = 1, second declared variable "Enum" +// if (l_pVar->m_bUsed) +// { +// l_pVar->m_qwValue = ((sTest1*)i_pData)->m_eEnum; +// } +// +// l_pVar = m_cVars[2]; //Index = 2, third declared variable "Text" +// if (l_pVar->m_bUsed) +// { +// l_pVar->m_pValue = ((sTest1*)i_pData)->m_pText; +// +// //Very important to set Text length !!!! +// if (l_pVar->m_pValue) +// { +// l_pVar->m_dwLength = PStrLen(l_pVar->m_pValue); +// } +// else +// { +// l_pVar->m_dwLength = 0; +// } +// } +// return TRUE; +// } +// }; +// +//////////////////////////////////////////////////////////////////////////////// +// int wmain(int i_iArgC, tXCHAR* i_pArgV[]) +// { +// CMy_Pred l_cPred; +// sTest1 l_sTest = {10, ETEST1_ENUM2, TM("My Name")}; +// +// if (FALSE == l_cPred.Set_Predicate(TM("$Enum$ <= \"ENUM2\" & ($Int$ >= \"0x9\" | $Text$ >> \"Andrey is My Name\")"))) +// { +// wprintf(l_cPred.Get_Error()); +// } +// +// if (l_cPred.Check(&l_sTest)) +// { +// wprintf(TM("TRUE\n")); +// } +// else +// { +// wprintf(TM("FALSE\n")); +// } +// +// return 0; +// } diff --git a/p7lib/Shared/QStringHelper.h b/p7lib/Shared/QStringHelper.h new file mode 100644 index 0000000..cb02161 --- /dev/null +++ b/p7lib/Shared/QStringHelper.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef QSTRING_HELPER_H +#define QSTRING_HELPER_H + +#if defined(UTF8_ENCODING) + #define XCHAR_TO_QSTRING(X) QString::fromUtf8(X) +#else + #define XCHAR_TO_QSTRING(X) QString::fromWCharArray(X) +#endif + +#if defined(UTF8_ENCODING) + #define QSTRING_TO_XCHAR_TRANSLATE(QbAUniq, QStr, XChar)\ + QByteArray QbAUniq = QStr.toUtf8();\ + XChar = (const tXCHAR*)QbAUniq.constData() + #define QSTRING_TO_XCHAR(QStr, XChar) QSTRING_TO_XCHAR_TRANSLATE(MAKE_UNIQUE(QbA), QStr, XChar) +#else + #define QSTRING_TO_XCHAR_TRANSLATE(QbAUniq, QStr, XChar)\ + QString QbAUniq = QStr;\ + XChar = (const tXCHAR*)QbAUniq.utf16() + #define QSTRING_TO_XCHAR(QStr, XChar) QSTRING_TO_XCHAR_TRANSLATE(MAKE_UNIQUE(QbA), QStr, XChar) +#endif + + +#endif //QSTRING_HELPER_H diff --git a/p7lib/Shared/RBTree.h b/p7lib/Shared/RBTree.h new file mode 100644 index 0000000..8194cf7 --- /dev/null +++ b/p7lib/Shared/RBTree.h @@ -0,0 +1,867 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//****************************************************************************** +// This header file contains red black tree pooled implementation * +// - http://www.rsdn.ru/article/alg/binstree.xml * +// - http://algolist.manual.ru/ds/rbtree.php * +// - http://rain.ifmo.ru/cat/view.php/vis/trees/red-black-2002 * +//****************************************************************************** +#ifndef RBTREE_H +#define RBTREE_H + + +#define RBT_NODE_RED (1) +#define RBT_NODE_BLACK (0) + +template +class CRBTree +{ +protected: + struct sNode + { + sNode *pLeft; + sNode *pRight; + sNode *pParent; + tData_Type tData; + tACHAR bColor; + }; + + struct tPool_Segment + { + sNode *m_pNodes; + tUINT32 m_dwCount; + tPool_Segment *m_pNext; + }; + + tPool_Segment *m_pPool_First; + sNode *m_pPool_Node_First; + //count of cell allocated for every pool segment + tUINT32 m_dwPool_Size; + + tBOOL m_bData_Free; + + sNode m_sSentinel;// = { m_pNIL, m_pNIL, 0, RBT_NODE_BLACK, 0}; + sNode *m_pRoot; // = m_pNIL; + sNode *m_pNIL; // &m_sSentinel +public: + //////////////////////////////////////////////////////////////////////////// + //CRBTree + CRBTree(tUINT32 i_dwPool_Size = 128, tBOOL i_bData_Free = TRUE) + { + m_pNIL = &m_sSentinel; + m_pRoot = m_pNIL; + + m_sSentinel.bColor = RBT_NODE_BLACK; + m_sSentinel.pParent = NULL; + m_sSentinel.tData = NULL; + m_sSentinel.pLeft = m_pNIL; + m_sSentinel.pRight = m_pNIL; + + m_dwPool_Size = i_dwPool_Size; + m_pPool_First = NULL; + m_pPool_Node_First = NULL; + + m_bData_Free = i_bData_Free; + }//CRBTree + + + //////////////////////////////////////////////////////////////////////////// + //~CRBTree + virtual ~CRBTree() + { + //delete all tree + Clear(); + + tPool_Segment *l_pPool_Tmp = NULL; + while (m_pPool_First) + { + l_pPool_Tmp = m_pPool_First; + m_pPool_First = m_pPool_First->m_pNext; + + Pool_Segment_Free(l_pPool_Tmp); + } + }//~CRBTree + + + //////////////////////////////////////////////////////////////////////////// + //Push + tData_Type Push(tData_Type i_pData, tKey_Type i_pKey) + { + sNode *l_pCurrent = m_pRoot; + sNode *l_pParent = NULL; + sNode *l_pNode = NULL; + + + //find where node belongs + while (m_pNIL != l_pCurrent) + { + if (Is_Qual(i_pKey, l_pCurrent->tData)) + { + return (l_pCurrent->tData); + } + else + { + l_pParent = l_pCurrent; + l_pCurrent = Is_Key_Less(i_pKey, l_pCurrent->tData) ? l_pCurrent->pLeft : l_pCurrent->pRight; + } + } + + l_pNode = Node_Allocate(); + + if (NULL == l_pNode) + { + return NULL; + } + + l_pNode->tData = i_pData; + l_pNode->pParent = l_pParent; + l_pNode->pLeft = m_pNIL; + l_pNode->pRight = m_pNIL; + l_pNode->bColor = RBT_NODE_RED; + + /* insert node in tree */ + if(l_pParent) + { + if(Is_Key_Less(i_pKey, l_pParent->tData)) + { + l_pParent->pLeft = l_pNode; + } + else + { + l_pParent->pRight = l_pNode; + } + } + else + { + m_pRoot = l_pNode; + } + + Fix_Push(l_pNode); + return l_pNode->tData; + }//Push + + + //////////////////////////////////////////////////////////////////////////// + //Del + void Del(sNode *i_pNode) + { + sNode *l_pX = NULL; + sNode *l_pY = NULL; + + if ( (NULL == i_pNode) + || (m_pNIL == i_pNode) + ) + { + return; + } + + if (m_bData_Free) + { + Data_Release(i_pNode->tData); + } + + if ( (m_pNIL == i_pNode->pLeft) + || (m_pNIL == i_pNode->pRight) + ) + { + //y has a m_pNIL node as a child + l_pY = i_pNode; + } + else + { + //find tree successor with a m_pNIL node as a child + l_pY = i_pNode->pRight; + while (m_pNIL != l_pY->pLeft) + { + l_pY = l_pY->pLeft; + } + } + + //x is y's only child + if (m_pNIL != l_pY->pLeft) + { + l_pX = l_pY->pLeft; + } + else + { + l_pX = l_pY->pRight; + } + + /* remove y from the parent chain */ + l_pX->pParent = l_pY->pParent; + if (l_pY->pParent) + { + if (l_pY == l_pY->pParent->pLeft) + { + l_pY->pParent->pLeft = l_pX; + } + else + { + l_pY->pParent->pRight = l_pX; + } + } + else + { + m_pRoot = l_pX; + } + + if (l_pY != i_pNode) + { + i_pNode->tData = l_pY->tData; + } + + if (l_pY->bColor == RBT_NODE_BLACK) + { + Fix_Del (l_pX); + } + + Node_Free(l_pY); + }//Del + + + //////////////////////////////////////////////////////////////////////////// + //Find + tData_Type Find(tKey_Type i_pKey) + { + sNode *l_pCurrent = m_pRoot; + while (m_pNIL != l_pCurrent) + { + if(Is_Qual(i_pKey, l_pCurrent->tData)) + { + return (l_pCurrent->tData); + } + else + { + l_pCurrent = Is_Key_Less (i_pKey, l_pCurrent->tData) + ? l_pCurrent->pLeft + : l_pCurrent->pRight; + } + } + + return NULL; + }//Find + + + //////////////////////////////////////////////////////////////////////////// + //Clear + void Clear() + { + if (m_pNIL == m_pRoot) + { + return; + } + + Clear(m_pRoot); + m_pRoot = m_pNIL; + }//Clear + + + //////////////////////////////////////////////////////////////////////////// + //Get_Depth + void Get_Depth(tUINT32 *o_pMin, tUINT32 *o_pMax) + { + if ( (NULL == o_pMin) + || (NULL == o_pMax) + ) + { + return; + } + + *o_pMin = ((tUINT32)~((tUINT32)0)); //max possible value + *o_pMax = 0; + + if (m_pNIL != m_pRoot) + { + Get_Depth(m_pRoot, o_pMin, o_pMax, 0); + } + }//Get_Depth + +private: + //////////////////////////////////////////////////////////////////////////// + //Pool_Segment_Create + tBOOL Pool_Segment_Create() + { + tBOOL l_bReturn = FALSE; + + tPool_Segment *l_pPool = (tPool_Segment*)MemAlloc(sizeof(tPool_Segment)); + + if (l_pPool) + { + memset(l_pPool, 0, sizeof(tPool_Segment)); + l_pPool->m_dwCount = m_dwPool_Size; + l_pPool->m_pNodes = (sNode*)MemAlloc(sizeof(sNode) * l_pPool->m_dwCount); + + if (l_pPool->m_pNodes) + { + sNode *l_pNode = NULL; + + memset(l_pPool->m_pNodes, + 0, + sizeof(tPool_Segment) * l_pPool->m_dwCount + ); + + l_pNode = l_pPool->m_pNodes; + + for (tUINT32 l_dwIDX = 1; l_dwIDX < l_pPool->m_dwCount; l_dwIDX++) + { + l_pNode->pRight = (l_pNode + 1); + l_pNode ++; + } + + l_bReturn = TRUE; + l_pPool->m_pNext = m_pPool_First; + m_pPool_First = l_pPool; + l_pNode->pRight = m_pPool_Node_First; + m_pPool_Node_First = l_pPool->m_pNodes; + } + } + + if (FALSE == l_bReturn) + { + Pool_Segment_Free(l_pPool); + } + + return l_bReturn; + }//Pool_Segment_Create + + + //////////////////////////////////////////////////////////////////////////// + //Pool_Segment_Free + void Pool_Segment_Free(tPool_Segment *io_pPool) + { + if (io_pPool) + { + if (io_pPool->m_pNodes) + { + MemFree(io_pPool->m_pNodes); + io_pPool->m_pNodes = NULL; + } + MemFree(io_pPool); + } + }//Pool_Segment_Free + + + //////////////////////////////////////////////////////////////////////////// + //Clear + void Clear(sNode *i_pNode) + { + if (m_pNIL != i_pNode->pLeft) + { + Clear(i_pNode->pLeft); + } + + if (m_pNIL != i_pNode->pRight) + { + Clear(i_pNode->pRight); + } + + if (m_bData_Free) + { + Data_Release(i_pNode->tData); + } + + if (i_pNode->pParent) + { + if (i_pNode == i_pNode->pParent->pRight) + { + i_pNode->pParent->pRight = m_pNIL; + } + else + { + i_pNode->pParent->pLeft = m_pNIL; + } + } + + Node_Free(i_pNode); + }//Clear + + + //////////////////////////////////////////////////////////////////////////// + //Get_Depth + void Get_Depth(sNode *i_pNode, + tUINT32 *o_pMin, + tUINT32 *o_pMax, + tUINT32 i_dwCurrent + ) + { + i_dwCurrent ++; + + if ( (m_pNIL == i_pNode->pLeft) + && (m_pNIL == i_pNode->pRight) + ) + { + if (i_dwCurrent < (*o_pMin)) + { + *o_pMin = i_dwCurrent; + } + + if (i_dwCurrent > (*o_pMax)) + { + *o_pMax = i_dwCurrent; + } + } + else + { + if (m_pNIL != i_pNode->pLeft) + { + Get_Depth(i_pNode->pLeft, o_pMin, o_pMax, i_dwCurrent); + } + + if (m_pNIL != i_pNode->pRight) + { + Get_Depth(i_pNode->pRight, o_pMin, o_pMax, i_dwCurrent); + } + } + }//Get_Depth + + + //////////////////////////////////////////////////////////////////////////// + //Rotate_Left + void Rotate_Left(sNode *i_pNode) + { + sNode *l_pNodeR = i_pNode->pRight; + + i_pNode->pRight = l_pNodeR->pLeft; + if (m_pNIL != l_pNodeR->pLeft) + { + l_pNodeR->pLeft->pParent = i_pNode; + } + + if (m_pNIL != l_pNodeR) + { + l_pNodeR->pParent = i_pNode->pParent; + } + + if (i_pNode->pParent) + { + if (i_pNode == i_pNode->pParent->pLeft) + { + i_pNode->pParent->pLeft = l_pNodeR; + } + else + { + i_pNode->pParent->pRight = l_pNodeR; + } + } + else + { + m_pRoot = l_pNodeR; + } + + l_pNodeR->pLeft = i_pNode; + if (m_pNIL != i_pNode) + { + i_pNode->pParent = l_pNodeR; + } + }//Rotate_Left + + + //////////////////////////////////////////////////////////////////////////// + //Rotate_Right + void Rotate_Right(sNode *i_pNode) + { + sNode *l_pNodeL = i_pNode->pLeft; + + i_pNode->pLeft = l_pNodeL->pRight; + if (m_pNIL != l_pNodeL->pRight) + { + l_pNodeL->pRight->pParent = i_pNode; + } + + if (m_pNIL != l_pNodeL) + { + l_pNodeL->pParent = i_pNode->pParent; + } + + if (i_pNode->pParent) + { + if (i_pNode == i_pNode->pParent->pRight) + { + i_pNode->pParent->pRight = l_pNodeL; + } + else + { + i_pNode->pParent->pLeft = l_pNodeL; + } + } + else + { + m_pRoot = l_pNodeL; + } + + l_pNodeL->pRight = i_pNode; + + if (m_pNIL != i_pNode) + { + i_pNode->pParent = l_pNodeL; + } + }//Rotate_Right + + + //////////////////////////////////////////////////////////////////////////// + //Fix_Push + void Fix_Push(sNode *i_pNode) + { + while ( (i_pNode != m_pRoot) + && (RBT_NODE_RED == i_pNode->pParent->bColor) + ) + { + // we have a violation + if (i_pNode->pParent == i_pNode->pParent->pParent->pLeft) + { + sNode *l_pUncle = i_pNode->pParent->pParent->pRight; + if (RBT_NODE_RED == l_pUncle->bColor) + { + i_pNode->pParent->bColor = RBT_NODE_BLACK; + l_pUncle->bColor = RBT_NODE_BLACK; + i_pNode->pParent->pParent->bColor = RBT_NODE_RED; + i_pNode = i_pNode->pParent->pParent; + } + else //(RBT_NODE_BLACK == l_pUncle->bColor) + { + if (i_pNode == i_pNode->pParent->pRight) + { + /* make x a left child */ + i_pNode = i_pNode->pParent; + Rotate_Left(i_pNode); + } + + /* recolor and rotate */ + i_pNode->pParent->bColor = RBT_NODE_BLACK; + i_pNode->pParent->pParent->bColor = RBT_NODE_RED; + Rotate_Right(i_pNode->pParent->pParent); + } + } + else //(i_pNode->pParent == i_pNode->pParent->pParent->pRight) + { + sNode *l_pUncle = i_pNode->pParent->pParent->pLeft; + if (RBT_NODE_RED == l_pUncle->bColor) + { + i_pNode->pParent->bColor = RBT_NODE_BLACK; + l_pUncle->bColor = RBT_NODE_BLACK; + i_pNode->pParent->pParent->bColor = RBT_NODE_RED; + i_pNode = i_pNode->pParent->pParent; + } + else //(RBT_NODE_BLACK == l_pUncle->bColor) + { + if (i_pNode == i_pNode->pParent->pLeft) + { + i_pNode = i_pNode->pParent; + Rotate_Right(i_pNode); + } + + i_pNode->pParent->bColor = RBT_NODE_BLACK; + i_pNode->pParent->pParent->bColor = RBT_NODE_RED; + Rotate_Left(i_pNode->pParent->pParent); + } + } + } + + m_pRoot->bColor = RBT_NODE_BLACK; + }//Fix_Push + + + //////////////////////////////////////////////////////////////////////////// + //Fix_Del + void Fix_Del(sNode *i_pNode) + { + while ( (i_pNode != m_pRoot) + && (RBT_NODE_BLACK == i_pNode->bColor) + ) + { + if (i_pNode == i_pNode->pParent->pLeft) + { + sNode *l_pBrother = i_pNode->pParent->pRight; + if (RBT_NODE_RED == l_pBrother->bColor) + { + l_pBrother->bColor = RBT_NODE_BLACK; + i_pNode->pParent->bColor = RBT_NODE_RED; + Rotate_Left(i_pNode->pParent); + l_pBrother = i_pNode->pParent->pRight; + } + + if ( (RBT_NODE_BLACK == l_pBrother->pLeft->bColor) + && (RBT_NODE_BLACK == l_pBrother->pRight->bColor) + ) + { + l_pBrother->bColor = RBT_NODE_RED; + i_pNode = i_pNode->pParent; + } + else + { + if (RBT_NODE_BLACK == l_pBrother->pRight->bColor) + { + l_pBrother->pLeft->bColor = RBT_NODE_BLACK; + l_pBrother->bColor = RBT_NODE_RED; + Rotate_Right (l_pBrother); + l_pBrother = i_pNode->pParent->pRight; + } + l_pBrother->bColor = i_pNode->pParent->bColor; + i_pNode->pParent->bColor = RBT_NODE_BLACK; + l_pBrother->pRight->bColor = RBT_NODE_BLACK; + Rotate_Left (i_pNode->pParent); + i_pNode = m_pRoot; + } + } + else + { + sNode *l_pBrother = i_pNode->pParent->pLeft; + if (RBT_NODE_RED == l_pBrother->bColor) + { + l_pBrother->bColor = RBT_NODE_BLACK; + i_pNode->pParent->bColor = RBT_NODE_RED; + Rotate_Right (i_pNode->pParent); + l_pBrother = i_pNode->pParent->pLeft; + } + if ( (RBT_NODE_BLACK == l_pBrother->pRight->bColor) + && (RBT_NODE_BLACK == l_pBrother->pLeft->bColor) + ) + { + l_pBrother->bColor = RBT_NODE_RED; + i_pNode = i_pNode->pParent; + } + else + { + if (RBT_NODE_BLACK == l_pBrother->pLeft->bColor) + { + l_pBrother->pRight->bColor = RBT_NODE_BLACK; + l_pBrother->bColor = RBT_NODE_RED; + Rotate_Left (l_pBrother); + l_pBrother = i_pNode->pParent->pLeft; + } + l_pBrother->bColor = i_pNode->pParent->bColor; + i_pNode->pParent->bColor = RBT_NODE_BLACK; + l_pBrother->pLeft->bColor = RBT_NODE_BLACK; + Rotate_Right (i_pNode->pParent); + i_pNode = m_pRoot; + } + } + } + + i_pNode->bColor = RBT_NODE_BLACK; + }//Fix_Del + +protected: + //////////////////////////////////////////////////////////////////////////// + // Data_Release + // override this function in derived class to implement specific data + // destructor(structures as example) + virtual tBOOL Data_Release(tData_Type i_pData) + { + if (NULL == i_pData) + { + return FALSE; + } + + delete i_pData; + return TRUE; + }// Data_Release + + + //////////////////////////////////////////////////////////////////////////// + //MemAlloc + //override this function in derived class to implement own memory allocation + //mechanism, it will be used everywhere in this class + virtual void *MemAlloc(size_t i_szSize) + { + return new tUINT8[i_szSize]; + }//MemAlloc + + + //////////////////////////////////////////////////////////////////////////// + // + //override this function in derived class to implement own memory deallocation + //mechanism, it will be used everywhere in this class + virtual void MemFree(void * i_pMemory) + { + delete [] ((tUINT8*)i_pMemory); + } + + + //////////////////////////////////////////////////////////////////////////// + //Node_Allocate + virtual sNode *Node_Allocate() + { + sNode *l_pReturn = NULL; + if (NULL == m_pPool_Node_First) + { + Pool_Segment_Create(); + } + + l_pReturn = m_pPool_Node_First; + + if (m_pPool_Node_First) + { + m_pPool_Node_First = m_pPool_Node_First->pRight; + } + + return l_pReturn; + }//Node_Allocate + + + //////////////////////////////////////////////////////////////////////////// + //Node_Free + virtual void Node_Free(sNode *i_pNode) + { + memset(i_pNode, 0, sizeof(sNode)); + i_pNode->pRight = m_pPool_Node_First; + m_pPool_Node_First = i_pNode; + }//Node_Free + + + //////////////////////////////////////////////////////////////////////////// + // This is abstract functions, you should to implement them // + //////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + virtual tBOOL Is_Key_Less(tKey_Type i_pKey, tData_Type i_pData) = 0; + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + virtual tBOOL Is_Qual(tKey_Type i_pKey, tData_Type i_pData) = 0; +}; + + + + +//////////////////////////////////////////////////////////////////////////////// +// TEST // +//////////////////////////////////////////////////////////////////////////////// + +// #include +// #include +// #include +// +// #include "RBTree.h" +// +// #define _CRTDBG_MAP_ALLOC +// #include +// +// struct sInt +// { +// int val; +// }; +// +// +// class CIntMap: +// public CRBTree +// { +// public: +// CIntMap(): +// CRBTree(1024, FALSE) +// { +// +// } +// protected: +// //////////////////////////////////////////////////////////////////////////// +// //Return +// //TRUE - if (i_pKey < i_pData::key) +// //FALSE - otherwise +// tBOOL Is_Key_Less(int i_iKey, sInt *i_pData) +// { +// return (i_iKey < i_pData->val); +// } +// +// //////////////////////////////////////////////////////////////////////////// +// //Return +// //TRUE - if (i_pKey == i_pData::key) +// //FALSE - otherwise +// virtual tBOOL Is_Qual(int i_iKey, sInt *i_pData) +// { +// return (i_iKey == i_pData->val); +// } +// +// }; +// +// +// int wmain(int argc, wchar_t* argv[]) +// { +// CIntMap *l_pMap = new CIntMap(); +// tUINT32 l_dwMax = 1000000; +// sInt *l_pInt = new sInt[l_dwMax]; +// tUINT32 l_dwMiss = 0; +// +// +// for (tUINT32 l_dwIteration = 0; l_dwIteration < 1000; l_dwIteration++) +// { +// l_dwMiss = 0; +// srand(l_dwIteration); +// +// for (tUINT32 l_dwIDX = 0; l_dwIDX < l_dwMax; l_dwIDX++) +// { +// l_pInt[l_dwIDX].val = rand()*rand(); +// +// if (&l_pInt[l_dwIDX] != l_pMap->Push(&l_pInt[l_dwIDX], l_pInt[l_dwIDX].val)) +// { +// l_dwMiss ++; +// } +// } +// +// tUINT32 l_dwDMin = 0; +// tUINT32 l_dwDMax = 0; +// l_pMap->Get_Depth(&l_dwDMin, &l_dwDMax); +// +// printf("Iteration[%d] Miss count = %d, Depth = %d/%d\n", +// l_dwIteration, +// l_dwMiss, +// l_dwDMin, +// l_dwDMax +// ); +// +// if ((l_dwDMin * 2) < l_dwDMax) +// { +// printf("Depth error = %d/%d\n", l_dwDMin, l_dwDMax); +// } +// +// l_pMap->Clear(); +// +// if ((_kbhit()) && (27 == _getwch())) +// { +// wprintf(L"... exiting\n"); +// break; +// } +// } +// +// +// delete l_pMap; +// +// delete [] l_pInt; +// +// //#ifndef NDEBUG +// // +// //int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag +// // +// //flag |= _CRTDBG_LEAK_CHECK_DF; // Turn on leak-checking bit +// // +// //_CrtSetDbgFlag(flag); // Set flag to the new value +// // +// //#endif +// +// _CrtDumpMemoryLeaks(); +// +// return 0; +// } + + +#endif //RBTREE_H diff --git a/p7lib/Shared/RingBuffer.h b/p7lib/Shared/RingBuffer.h new file mode 100644 index 0000000..766cf14 --- /dev/null +++ b/p7lib/Shared/RingBuffer.h @@ -0,0 +1,244 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef RING_BUFFER_H +#define RING_BUFFER_H + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class CRingBuffer +{ +public: + tUINT8 *m_pBufferHead; + tUINT8 *m_pBufferTail; + size_t m_szBuffer; + size_t m_szWritten; + tUINT8 *m_pWrite; + tUINT8 *m_pRead; + tUINT64 m_qwMarker; +public: + CRingBuffer(size_t i_szBuffer) + : m_pBufferHead(NULL) + , m_pBufferTail(NULL) + , m_szBuffer(i_szBuffer) + , m_szWritten(0) + , m_pWrite(NULL) + , m_pRead(NULL) + , m_qwMarker(0xDEADBEEFBEEFDEADull) + { + m_pBufferHead = (tUINT8*)malloc(i_szBuffer + sizeof(m_qwMarker)); + if (m_pBufferHead) + { + m_pBufferTail = m_pBufferHead + m_szBuffer; + memcpy(m_pBufferTail, &m_qwMarker, sizeof(m_qwMarker)); + } + + + m_pWrite = m_pBufferHead; + m_pRead = m_pBufferHead; + } + + virtual ~CRingBuffer() + { + if (m_pBufferHead) + { + if (0 != memcmp(m_pBufferTail, &m_qwMarker, sizeof(m_qwMarker))) + { + printf("CRingBuffer has been corrupted!"); + } + + free(m_pBufferHead); + m_pBufferHead = NULL; + } + + m_pBufferHead = NULL; + m_pBufferTail = NULL; + m_szBuffer = 0; + m_pWrite = NULL; + m_pRead = NULL; + m_szWritten = 0; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline size_t GetFreeSize() + { + return m_szBuffer - m_szWritten; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline size_t GetSize() + { + return m_szBuffer; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline size_t GetUsedSize() + { + return m_szWritten; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline tUINT8* GetReadHead(size_t &o_rSize) + { + if (!m_szWritten) + { + o_rSize = 0; + return NULL; + } + + + if (m_pWrite > m_pRead) + { + o_rSize = m_pWrite - m_pRead; + } + else + { + o_rSize = m_pBufferTail - m_pRead; + } + + return m_pRead; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline bool MoveReadHead(size_t o_szIncrease) + { + if (o_szIncrease > m_szWritten) + { + return false; + } + + if (m_pWrite > m_pRead) + { + m_pRead += o_szIncrease; + m_szWritten -= o_szIncrease; + return true; + } + else + { + size_t l_szTail = m_pBufferTail - m_pRead; + + if (o_szIncrease > l_szTail) + { + return false; //impossible to get continuous buffer consisting of 2 parts :) + } + else + { + m_szWritten -= o_szIncrease; + m_pRead += o_szIncrease; + + if (m_pRead >= m_pBufferTail) + { + m_pRead = m_pBufferHead; + } + + return true; + } + } + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + __forceinline bool Write(const tUINT8 *i_pData, size_t i_szData) + { + if (i_szData > (m_szBuffer - m_szWritten)) + { + return false; + } + + m_szWritten += i_szData; + + if (m_pWrite < m_pRead) + { + memcpy(m_pWrite, i_pData, i_szData); + m_pWrite += i_szData; + } + else + { + size_t l_szTail = m_pBufferTail - m_pWrite; + if (i_szData < l_szTail) + { + memcpy(m_pWrite, i_pData, i_szData); + m_pWrite += i_szData; + } + else + { + memcpy(m_pWrite, i_pData, l_szTail); + i_pData += l_szTail; + i_szData -= l_szTail; + + memcpy(m_pBufferHead, i_pData, i_szData); + + m_pWrite = m_pBufferHead + i_szData; + } + } + + return true; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline bool Read(tUINT8 *o_pData, size_t i_szData) + { + if (i_szData > GetUsedSize()) + { + return false; + } + + m_szWritten -= i_szData; + + if (m_pWrite > m_pRead) + { + memcpy(o_pData, m_pRead, i_szData); + m_pRead += i_szData; + } + else + { + size_t l_szTail = m_pBufferTail - m_pRead; + + if (i_szData >= l_szTail) + { + memcpy(o_pData, m_pRead, l_szTail); + o_pData += l_szTail; + i_szData -= l_szTail; + + memcpy(o_pData, m_pBufferHead, i_szData); + + m_pRead = m_pBufferHead + i_szData; + } + else + { + memcpy(o_pData, m_pRead, i_szData); + m_pRead += i_szData; + } + } + + + if (0 != memcmp(m_pBufferTail, &m_qwMarker, sizeof(m_qwMarker))) + { + printf("CRingBuffer has been corrupted!"); + } + + return true; + + } +}; + + +#endif //RING_BUFFER_H diff --git a/p7lib/Shared/SharedLib.h b/p7lib/Shared/SharedLib.h new file mode 100644 index 0000000..fbbe156 --- /dev/null +++ b/p7lib/Shared/SharedLib.h @@ -0,0 +1,63 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef ISHARED_LIB_H +#define ISHARED_LIB_H + +class CSharedLib +{ +protected: + tINT32 volatile m_lReference; + CWString m_cPath; + tBOOL m_bState; + +public: + CSharedLib(const tXCHAR *i_pPath) + : m_lReference(1) + , m_cPath(i_pPath) + , m_bState(FALSE) + { + } + + virtual void *GetFunction(const tACHAR *i_pName) = 0; + + tBOOL GetState() + { + return m_bState; + } + + tINT32 Add_Ref() + { + return ATOMIC_INC(&m_lReference); + } + + tINT32 Release() + { + tINT32 l_lResult = ATOMIC_DEC(&m_lReference); + if ( 0 >= l_lResult ) + { + delete this; + } + + return l_lResult; + } + + virtual ~CSharedLib() {} +}; + +#endif //ISHARED_LIB_H diff --git a/p7lib/Shared/Ticks.h b/p7lib/Shared/Ticks.h new file mode 100644 index 0000000..def43b4 --- /dev/null +++ b/p7lib/Shared/Ticks.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef TICKS_H +#define TICKS_H + + +//////////////////////////////////////////////////////////////////////////////// +class CTicks +{ +public: + static tUINT32 inline Difference(tUINT32 i_dwCur, tUINT32 i_dwPrev) + { + tUINT32 l_dwReturn = 0; + + if (i_dwCur >= i_dwPrev) + { + l_dwReturn = i_dwCur - i_dwPrev; + } + else + { + l_dwReturn = (0xFFFFFFFF - i_dwPrev) + i_dwCur; + } + + return l_dwReturn; + } +}; + +#endif //TICKS_H diff --git a/p7lib/Shared/UDP_NB.h b/p7lib/Shared/UDP_NB.h new file mode 100644 index 0000000..9fafbb6 --- /dev/null +++ b/p7lib/Shared/UDP_NB.h @@ -0,0 +1,709 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef UDP_NB_H +#define UDP_NB_H + +#include "PSocket.h" + + +#define SENT_SELECT_TIMEOUT (10) + +enum eSocket_Status +{ + UDP_SOCKET_OK = 0, + UDP_SOCKET_RECEIVE_ERROR , + UDP_SOCKET_SEND_ERROR , + UDP_SOCKET_CREATE_ERROR , + UDP_SOCKET_SELECT_ERROR , + UDP_SOCKET_WRONG_PARAMETERS , + UDP_SOCKET_NOT_INITIALIZED , + UDP_SOCKET_BIND_ERROR , + UDP_SOCKET_NOT_READY +}; + +enum eFD_Type +{ + FD_TYPE_WRITE, + FD_TYPE_READ +}; + + +//Uncomment this macro to artificially create network errors, allows to test +//protocols for durability, value is equal to % of errors +//#define UDP_SOCKET_ERRORS_CHANCE 2.0f + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over udp socket +class CUDP_Socket +{ +private: + tSOCKET m_hSocket; + IJournal *m_pLog; + tBOOL m_bServer; + sockaddr_storage m_tAddress; + tUINT32 m_dwAddress_Size; + tINT32 m_iFamily; + + tINT32 m_iSndBufSize; + tINT32 m_iRcvBufSize; +public: + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::CUDP_Socket + CUDP_Socket(IJournal *i_pLog, + sockaddr *i_pAddress, + tBOOL i_bServer) + : m_hSocket(INVALID_SOCKET_VAL) + , m_pLog(i_pLog) + , m_bServer(i_bServer) + , m_dwAddress_Size(0) + , m_iFamily(AF_UNSPEC) + , m_iSndBufSize(CLIENT_SEND_BUFFER_SIZE) + , m_iRcvBufSize(CLIENT_RECV_BUFFER_SIZE) + { + eSocket_Status l_eStatus = UDP_SOCKET_OK; + + if (m_pLog) + { + m_pLog->Add_Ref(); + } + + if (NULL == i_pAddress) + { + l_eStatus = UDP_SOCKET_WRONG_PARAMETERS; + JOURNAL_ERROR(m_pLog, TM("NULL == i_pAddress")); + } + + if (UDP_SOCKET_OK == l_eStatus ) + { + memset(&m_tAddress, 0, sizeof(sockaddr_storage)); + + m_iFamily = i_pAddress->sa_family; + if (AF_INET == i_pAddress->sa_family) + { + m_dwAddress_Size = sizeof(sockaddr_in); + memcpy(&m_tAddress, i_pAddress, m_dwAddress_Size); + } + else if (AF_INET6 == i_pAddress->sa_family) + { + m_dwAddress_Size = sizeof(sockaddr_in6); + memcpy(&m_tAddress, i_pAddress, m_dwAddress_Size); + } + else + { + l_eStatus = UDP_SOCKET_WRONG_PARAMETERS; + JOURNAL_ERROR(m_pLog, + TM("Address family is wrong = %d"), + (tUINT32)m_iFamily); + } + + } + + if (UDP_SOCKET_OK == l_eStatus ) + { + XCHAR l_pIP[128] = TM("?"); + tUINT32 l_dwLength = sizeof(l_pIP) / sizeof(l_pIP[0]); + + if (Print_SAddr(i_pAddress, l_pIP, l_dwLength)) + { + JOURNAL_INFO(m_pLog, TM("Use address = %s"), l_pIP); + } + + l_eStatus = Create_Socket(m_iFamily); + } + + //m_pAddress.sin_family = AF_INET; + //m_pAddress.sin_addr.s_addr = inet_addr(i_pIP); + //m_pAddress.sin_port = htons(i_wPort); + + if (UDP_SOCKET_OK == l_eStatus ) + { + if (m_bServer) + { + m_iSndBufSize = SERVER_SEND_BUFFER_SIZE; + m_iRcvBufSize = SERVER_RECV_BUFFER_SIZE; + + if (0 != bind(m_hSocket, (sockaddr*)&m_tAddress, m_dwAddress_Size)) + { + JOURNAL_ERROR(m_pLog, + TM("Bind failed, error=%d !"), + (tUINT32)GET_SOCKET_ERROR() + ); + + l_eStatus = UDP_SOCKET_BIND_ERROR; + } + else + { + tINT32 l_iFlagRcv = SERVER_RECV_BUFFER_SIZE; + tINT32 l_iFlagSnd = SERVER_SEND_BUFFER_SIZE; + + if ( (0 != setsockopt(m_hSocket, SOL_SOCKET, SO_RCVBUF, (char*)&l_iFlagRcv, sizeof(l_iFlagRcv))) + || (0 != setsockopt(m_hSocket, SOL_SOCKET, SO_SNDBUF, (char*)&l_iFlagSnd, sizeof(l_iFlagSnd))) + ) + { + JOURNAL_ERROR(m_pLog, TM("Failed to set socket options, error=%d !"), (tUINT32)GET_SOCKET_ERROR()); + } + + tINT32 l_iFlag = 0; + socklen_t l_szFlag = (socklen_t)sizeof(l_iFlag); + + if (0 == getsockopt(m_hSocket, SOL_SOCKET, SO_RCVBUF, (char*)&l_iFlag, &l_szFlag)) + { + m_iRcvBufSize = l_iFlag; + } + + l_iFlag = 0; + l_szFlag = (socklen_t)sizeof(l_iFlag); + + if (0 == getsockopt(m_hSocket, SOL_SOCKET, SO_SNDBUF, (char*)&l_iFlag, &l_szFlag)) + { + m_iSndBufSize = l_iFlag; + } + } + } + else //not server + { + tINT32 l_iFlag = CLIENT_RECV_BUFFER_SIZE; + tINT32 l_iReal = 0; + socklen_t l_szSize = sizeof(l_iFlag); + + if (SOCKET_ERROR == setsockopt(m_hSocket, + SOL_SOCKET, + SO_RCVBUF, + (char*)&l_iFlag, + sizeof(l_iFlag) + ) + ) + { + JOURNAL_ERROR(m_pLog, + TM("setsockopt fail, error=%d !"), + GET_SOCKET_ERROR() + ); + } + + if (SOCKET_ERROR == getsockopt(m_hSocket, + SOL_SOCKET, + SO_RCVBUF, + (char*)&l_iReal, + &l_szSize + ) + ) + { + JOURNAL_ERROR(m_pLog, + TM("getsockopt fail, error=%d !"), + GET_SOCKET_ERROR() + ); + } + else + { + m_iRcvBufSize = l_iReal; + if (l_iReal != l_iFlag) + { + JOURNAL_WARNING(m_pLog, + TM("Socket receive buffer != necessary %d/%d"), + l_iReal, + l_iFlag + ); + } + } + + l_iFlag = CLIENT_SEND_BUFFER_SIZE; + if (SOCKET_ERROR == setsockopt(m_hSocket, + SOL_SOCKET, + SO_SNDBUF, + (char*)&l_iFlag, + sizeof(l_iFlag) + ) + ) + { + JOURNAL_ERROR(m_pLog, + TM("setsockopt fail, error=%d !"), + GET_SOCKET_ERROR() + ); + } + + if (SOCKET_ERROR == getsockopt(m_hSocket, + SOL_SOCKET, + SO_SNDBUF, + (char*)&l_iReal, + &l_szSize + ) + ) + { + JOURNAL_ERROR(m_pLog, + TM("getsockopt fail, error=%d !"), + GET_SOCKET_ERROR() + ); + } + else + { + m_iSndBufSize = l_iReal; + + if (l_iReal != l_iFlag) + { + JOURNAL_WARNING(m_pLog, + TM("Socket send buffer size is less than necessary %d/%d"), + l_iReal, + l_iFlag + ); + } + } + }//else //not server + } + + if (UDP_SOCKET_OK == l_eStatus ) + { + if (FALSE == Disable_PortUnreachable_ICMP(m_hSocket)) + { + JOURNAL_ERROR(m_pLog, + TM("WSAIoctl(SIO_UDP_CONNRESET), error=%d !"), + (tUINT32)GET_SOCKET_ERROR() + ); + } + } + + if ( (UDP_SOCKET_OK != l_eStatus) + && (INVALID_SOCKET_VAL != m_hSocket) + ) + { + CLOSE_SOCKET(m_hSocket); + m_hSocket = INVALID_SOCKET_VAL; + } + }//CUDP_Socket::CUDP_Socket + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::~CUDP_Socket + ~CUDP_Socket() + { + if (INVALID_SOCKET_VAL != m_hSocket) + { + CLOSE_SOCKET(m_hSocket); + m_hSocket = INVALID_SOCKET_VAL; + } + + if (m_pLog) + { + m_pLog->Release(); + m_pLog = NULL; + } + + }//CUDP_Socket::~CUDP_Socket + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Get_Address + sockaddr_storage *Get_Address() + { + return &m_tAddress; + }//CUDP_Socket::Get_Address + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Initialized + tBOOL Initialized() + { + return (INVALID_SOCKET_VAL != m_hSocket); + }//CUDP_Socket::Initialized + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::GetRecvBufferSize + tINT32 GetRecvBufferSize() + { + return m_iRcvBufSize; + }//CUDP_Socket::GetRecvBufferSize + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::GetSendBufferSize + tINT32 GetSendBufferSize() + { + return m_iSndBufSize; + }//CUDP_Socket::GetSendBufferSize + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Send + eSocket_Status Send(const char *i_pBuffer, tUINT32 i_dwSize) + { + return Send((sockaddr *)&m_tAddress, m_dwAddress_Size, i_pBuffer, i_dwSize); + }//CUDP_Socket::Send + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Send + eSocket_Status Send(sockaddr *i_pAddress, + tUINT32 i_dwAddress_Size, + const char *i_pBuffer, + tUINT32 i_dwSize + ) + { + eSocket_Status l_eResult = UDP_SOCKET_OK; + + if (INVALID_SOCKET_VAL == m_hSocket) + { + return UDP_SOCKET_NOT_INITIALIZED; + } + + #if defined(UDP_SOCKET_ERRORS_CHANCE) + { + tINT32 l_iChance = rand(); //it generate digits -32767 .. 0 .. 32767 + tINT32 l_iLimit = (tINT32)((32767.0f * UDP_SOCKET_ERRORS_CHANCE) / 100.0f); + + if (0 > l_iChance) l_iChance = -l_iChance; + + if (l_iLimit >= l_iChance) + { + if ((l_iLimit / 2) <= l_iChance) // 50% do not sent + { + return l_eResult; + } + else //50% damage size + { + i_dwSize = i_dwSize / 2; + } + } + } + #endif + + if ( (NULL == i_pBuffer) + || (NULL == i_pAddress) + || (0 == i_dwSize) + ) + { + return UDP_SOCKET_WRONG_PARAMETERS; + } + + tUINT32 l_dwSent = 0; + tINT32 l_iRes = SOCKET_ERROR; + eSocket_Status l_eReadyResult = UDP_SOCKET_OK; + + while (l_dwSent < i_dwSize) + { + l_eReadyResult = Is_Ready(FD_TYPE_WRITE, SENT_SELECT_TIMEOUT); + if (UDP_SOCKET_OK == l_eReadyResult) + { + l_iRes = sendto(m_hSocket, + i_pBuffer + l_dwSent, + i_dwSize - l_dwSent, + 0, + i_pAddress, + i_dwAddress_Size + ); + + if (SOCKET_ERROR == l_iRes) + { + JOURNAL_ERROR(m_pLog, + TM("Send fail, error=%d !"), + GET_SOCKET_ERROR() + ); + + l_eResult = UDP_SOCKET_SEND_ERROR; + break; + } + else + { + l_dwSent += l_iRes; + } + } + else if (UDP_SOCKET_NOT_READY != l_eReadyResult) + { + l_eResult = UDP_SOCKET_SELECT_ERROR; + break; + } + } + + return l_eResult; + }//CUDP_Socket::Send + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Recv + eSocket_Status Recv(sockaddr_storage *o_pAddress, + char *i_pBuffer, + tUINT32 i_dwSize, + tUINT32 *o_pReceived, + tUINT32 i_dwTimeOut + ) + { + eSocket_Status l_eResult = UDP_SOCKET_NOT_READY; + eSocket_Status l_eIs_Ready = Is_Ready(FD_TYPE_READ, i_dwTimeOut); + + if (UDP_SOCKET_OK == l_eIs_Ready) + { + l_eResult = Recv(o_pAddress, i_pBuffer, i_dwSize, o_pReceived); + } + else + { + if (UDP_SOCKET_NOT_READY != l_eIs_Ready) + { + l_eResult = UDP_SOCKET_SELECT_ERROR; + } + } + + return l_eResult; + }//CUDP_Socket::Recv + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Recv + //Before calling this function you should call Get_IMessage_Size(); + //if there is no message this function will block until message will be recv. + eSocket_Status Recv(sockaddr_storage *o_pAddress, + char *i_pBuffer, + tUINT32 i_dwSize, + tUINT32 *o_pReceived + ) + { + eSocket_Status l_eResult = UDP_SOCKET_OK; + + if (INVALID_SOCKET_VAL == m_hSocket) + { + return UDP_SOCKET_NOT_INITIALIZED; + } + + if ( (NULL == i_pBuffer) + || (NULL == o_pAddress) + || (NULL == o_pReceived) + || (0 == i_dwSize) + ) + { + return UDP_SOCKET_WRONG_PARAMETERS; + } + + tADDR_LEN l_lAddr_Size = sizeof(*o_pAddress); + *o_pReceived = 0; + + tINT32 l_lRecvRes = recvfrom(m_hSocket, + i_pBuffer, + i_dwSize, + 0, + (sockaddr*)o_pAddress, + &l_lAddr_Size + ); + + if (SOCKET_ERROR == l_lRecvRes) + { + JOURNAL_ERROR(m_pLog, + TM("recvfrom failed, error=%d !"), + GET_SOCKET_ERROR() + ); + + l_eResult = UDP_SOCKET_RECEIVE_ERROR; + } + else + { + *o_pReceived = l_lRecvRes; + } + + return l_eResult; + }//CUDP_Socket::Recv + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Peek + //This function can read part of the datagram (header for example) and + //datagram is not removed from queue + //Use it carefully, for your own risk + eSocket_Status Peek(char *i_pBuffer, + tUINT32 i_dwSize + ) + { + eSocket_Status l_eResult = UDP_SOCKET_OK; + + if (INVALID_SOCKET_VAL == m_hSocket) + { + return UDP_SOCKET_NOT_INITIALIZED; + } + + if ( (NULL == i_pBuffer) + || (0 == i_dwSize) + ) + { + return UDP_SOCKET_WRONG_PARAMETERS; + } + + tINT32 l_lRecvRes = recv(m_hSocket, + i_pBuffer, + i_dwSize, + MSG_PEEK + ); + + if (SOCKET_ERROR == l_lRecvRes) + { + tINT32 l_iError = GET_SOCKET_ERROR(); +#if defined(_WIN32) || defined(_WIN64) + if (WSAEMSGSIZE != l_iError) +#endif + { + + JOURNAL_ERROR(m_pLog, + TM("recvfrom failed, error=%d !"), + l_iError + ); + + l_eResult = UDP_SOCKET_RECEIVE_ERROR; + } + } + else if (0 >= l_lRecvRes) + { + l_eResult = UDP_SOCKET_NOT_READY; + } + + return l_eResult; + }//CUDP_Socket::Peek + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Is_Server_Address + tBOOL Is_Server_Address(sockaddr_storage *i_pAddress) + { + if ( (NULL == i_pAddress) + || (TRUE == m_bServer) + || (i_pAddress->ss_family != m_tAddress.ss_family) + ) + { + return FALSE; + } + + if ( (AF_INET == i_pAddress->ss_family) + && (((sockaddr_in*)i_pAddress)->sin_port == ((sockaddr_in*)&m_tAddress)->sin_port) + && (((sockaddr_in*)i_pAddress)->sin_addr.s_addr == ((sockaddr_in*)&m_tAddress)->sin_addr.s_addr) + ) + { + return TRUE; + } + else if ( (AF_INET6 == i_pAddress->ss_family) + && (((sockaddr_in6*)i_pAddress)->sin6_port == ((sockaddr_in6*)&m_tAddress)->sin6_port) + && (0 == memcmp(&((sockaddr_in6*)i_pAddress)->sin6_addr, + &((sockaddr_in6*)&m_tAddress)->sin6_addr, + sizeof(in6_addr) + ) + ) + ) + { + return TRUE; + } + + return FALSE; + }//CUDP_Socket::Is_Server_Address + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Is_Ready + eSocket_Status Is_Ready(eFD_Type i_eType, tUINT32 i_dwTimeOut) + { + eSocket_Status l_eReturn = UDP_SOCKET_NOT_READY; + + if (INVALID_SOCKET_VAL == m_hSocket) + { + return UDP_SOCKET_NOT_INITIALIZED; + } + + tINT32 l_iSelect = SOCKET_ERROR; + fd_set l_pFDS; + timeval l_tTimeOut; + + l_tTimeOut.tv_sec = 0; + l_tTimeOut.tv_usec = i_dwTimeOut * 1000; + + FD_ZERO(&l_pFDS); + FD_SET((tUINT32)m_hSocket, &l_pFDS); + + if (FD_TYPE_READ == i_eType) + { + l_iSelect = select(((tUINT32)m_hSocket) + 1, + &l_pFDS, + NULL, + NULL, + &l_tTimeOut + ); + } + else + { + l_iSelect = select(((tUINT32)m_hSocket) + 1, + NULL, + &l_pFDS, + NULL, + &l_tTimeOut + ); + } + + if (SOCKET_ERROR == l_iSelect) + { + JOURNAL_ERROR(m_pLog, + TM("Select fail, error=%d !"), + GET_SOCKET_ERROR() + ); + + l_eReturn = UDP_SOCKET_SELECT_ERROR; + } + else if ( (l_iSelect > 0) + && (FD_ISSET(m_hSocket, &l_pFDS)) + ) + { + l_eReturn = UDP_SOCKET_OK; + } + + return l_eReturn; + }//CUDP_Socket::Is_Ready + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Create_Socket + eSocket_Status Create_Socket(tINT32 i_iFamily) + { + m_hSocket = socket(i_iFamily, SOCK_DGRAM, IPPROTO_UDP); + if (INVALID_SOCKET_VAL == m_hSocket) + { + JOURNAL_ERROR(m_pLog, + TM("Socket creation failed, error=%d !"), + GET_SOCKET_ERROR() + ); + + return UDP_SOCKET_CREATE_ERROR; + } + + return UDP_SOCKET_OK; + }//CUDP_Socket::Create_Socket + + + //////////////////////////////////////////////////////////////////////////// + //CUDP_Socket::Get_Input_Data_Size + //Not used + //tUINT32 Get_Input_Data_Size() + //{ + // tUINT32 l_dwResult = 0; + // + // if (INVALID_SOCKET_VAL != m_hSocket) + // { + // Use to determine the amount of data pending in the network's input + // buffer that can be read from socket s. The argp parameter points to an unsigned long value in which ioctlsocket stores the result. FIONREAD returns the amount of data that can be read in a single call to the recv function, which may not be the same as the total amount of data queued on the socket. If s is message oriented (for example, type SOCK_DGRAM), FIONREAD still returns the amount of pending data in the network buffer, however, the amount that can actually be read in a single call to the recv function is limited to the data size written in the send or sendto function call. + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx + // + // if (NO_ERROR != ioctlsocket(m_hSocket, FIONREAD, &l_dwResult)) + // { + // l_dwResult = 0; + // } + // } + // + // return l_dwResult; + //}//CUDP_Socket::Get_Input_Data_Size + + +};//CUDP_Socket + + +#endif //UDP_NB \ No newline at end of file diff --git a/p7lib/Shared/UTF.h b/p7lib/Shared/UTF.h new file mode 100644 index 0000000..8192698 --- /dev/null +++ b/p7lib/Shared/UTF.h @@ -0,0 +1,516 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef UTF_CONV_H +#define UTF_CONV_H + +//////////////////////////////////////////////////////////////////////////////// +// Basic UTF LE conversion functions +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//Get_utf8_Length +static UNUSED_FUNC size_t Get_UTF8_Length(const char *i_pText) +{ + size_t l_dwLength = 0; + unsigned char l_bCh = 0; + + if (NULL == i_pText) + { + return 0; + } + + while ( 0 != (*i_pText)) + { + l_bCh = *i_pText; + if (0x7F >= l_bCh) //1 char + { + i_pText += 1; + } + else if (0xE0 > l_bCh) //11100000b = 2 chars + { + i_pText += 2; + } + else if (0xF0 > l_bCh) //11110000b = 3 chars + { + i_pText += 3; + } + else if (0xF8 > l_bCh) //11111000b = 4 chars + { + i_pText += 4; + } + else if (0xFC > l_bCh) //11111100b = 5 chars + { + i_pText += 5; + } + else //6 chars + { + i_pText += 6; + } + + l_dwLength ++; + } + + return l_dwLength; +}//Get_utf8_Length + + +//////////////////////////////////////////////////////////////////////////////// +//Get_UTF16_Length +static UNUSED_FUNC size_t Get_UTF16_Length(const tWCHAR *i_pText) +{ + size_t l_dwLength = 0; + tWCHAR l_wCh = 0; + + if (NULL == i_pText) + { + return 0; + } + + while ( 0 != (*i_pText)) + { + l_wCh = *i_pText; + + if ( (l_wCh >= 0xD800ul) //processing surrogate pairs + && (l_wCh <= 0xDFFFul) + ) + { + i_pText += 2; + } + else + { + i_pText += 1; + } + + l_dwLength ++; + } + + return l_dwLength; +}//Get_UTF16_Length + + +//////////////////////////////////////////////////////////////////////////////// +//Get_UTF8_Bytes +//return: count characters in UTF-16 string +static UNUSED_FUNC size_t Get_UTF8_Stat(const tWCHAR *i_pStr, + size_t &o_rBytes, + size_t &o_rChars) +{ + size_t l_szReturn = 0; + tUINT32 l_dwCh = 0; + + if (NULL == i_pStr) + { + return -1; + } + + o_rBytes = 0; + o_rChars = 0; + + while (0ul != (*i_pStr)) + { + l_dwCh = (tUINT16)(*i_pStr); + + if ( (l_dwCh >= 0xD800ul) //processing surrogate pairs + && (l_dwCh <= 0xDFFFul) + ) + { + tUINT32 l_dwTrailing = (tUINT16)*(++i_pStr); + l_szReturn ++; + if ( (0xDC00ul <= l_dwTrailing) + && (0xDFFFul >= l_dwTrailing) + ) + { + l_dwCh = 0x10000ul + (((l_dwCh & 0x3FFul) << 10) | (l_dwTrailing & 0x3FFul)); + } + else //unexpected + { + l_dwCh = '?'; + } + } + + if (0x80 > l_dwCh) + { + o_rBytes++; + o_rChars++; + } + else if (0x800ul > l_dwCh) + { + o_rBytes += 2; + o_rChars++; + } + else if (0x10000ul > l_dwCh) + { + o_rBytes += 3; + o_rChars++; + } + else if (0x200000ul > l_dwCh) + { + o_rBytes += 4; + o_rChars++; + } + else + { + o_rBytes += 1; + o_rChars++; + } + + if (*i_pStr) + { + ++i_pStr; + ++l_szReturn; + } + else + { + break; + } + } + + return l_szReturn; +}//Get_UTF8_Bytes + + +//////////////////////////////////////////////////////////////////////////////// +//Convert_UTF8_To_UTF16 +//Warning: this function do not produce UTF-16 surrogate pairs - function replace +//surrogate pairs by '*' char. Surrogate pairs will be implemented in next life :-) +//Works only with LE +static UNUSED_FUNC tINT32 Convert_UTF8_To_UTF16(const char *i_pSrc, + tWCHAR *o_pDst, + tUINT32 i_dwMax_Len + ) +{ + tINT32 l_iLength = 0; + unsigned char l_bCh = 0; + + if ( (NULL == i_pSrc) + || (NULL == o_pDst) + || (0 >= i_dwMax_Len) + ) + { + return l_iLength; + } + + i_dwMax_Len -= 1; //reserve space to trailing \0; + + while ( ( 0 != (*i_pSrc)) + && (i_dwMax_Len > (tUINT32)l_iLength) + ) + { + l_bCh = *i_pSrc; + if (0x7F >= l_bCh) //1 char + { + *o_pDst = (tWCHAR)l_bCh; + } + else if (0xE0 > l_bCh) //11100000b = 2 chars + { + *o_pDst = (tWCHAR)((l_bCh & 0x1F) << 6); + *o_pDst |= (*(++i_pSrc) & 0x3F); + } + else if (0xF0 > l_bCh) //11110000b = 3 chars + { + *o_pDst = (tWCHAR)((l_bCh & 0xF) << 12); + *o_pDst |= (*(++i_pSrc) & 0x3F) << 6; + *o_pDst |= (*(++i_pSrc) & 0x3F); + } + else if (0xF8 > l_bCh) //11111000b = 4 chars + { + *o_pDst = (tWCHAR)'*'; + i_pSrc += 3; + } + else if (0xFC > l_bCh) //11111100b = 5 chars + { + *o_pDst = (tWCHAR)'*'; + i_pSrc += 4; + } + else //6 chars + { + *o_pDst = (tWCHAR)'*'; + i_pSrc += 5; + } + + o_pDst ++; + i_pSrc ++; + l_iLength ++; + } + + *o_pDst = 0; + + return l_iLength; +}//Convert_UTF8_To_UTF16 + + +//////////////////////////////////////////////////////////////////////////////// +//Convert_UTF32_To_UTF8 (LE) +//Return - count of the used bytes, except trailing 0, if destination buffer +//size is not enough to store whole source string, result will be truncated +static UNUSED_FUNC tINT32 Convert_UTF32_To_UTF8(const tUINT32 *i_pSrc, + tACHAR *o_pDst, + tUINT32 i_dwDst_Len + ) +{ + tINT32 l_iLength = i_dwDst_Len; + tUINT32 l_dwCh = 0; + + if ( (NULL == i_pSrc) + || (NULL == o_pDst) + || (0 >= i_dwDst_Len) + ) + { + return -1; + } + + while ( ( 0ul != (*i_pSrc)) + && (2 <= l_iLength) + ) + { + l_dwCh = (*i_pSrc); + + if (0x80 > l_dwCh) + { + *o_pDst = (tACHAR)(l_dwCh & 0x7Ful); + o_pDst ++; + l_iLength--; + } + else if (0x800ul > l_dwCh) + { + if (3 <= l_iLength) + { + *o_pDst = (tACHAR)(0xC0ul | ((l_dwCh >> 6) & 0x1Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 0) & 0x3Ful)); o_pDst ++; + l_iLength -= 2; + } + else + { + break; + } + } + else if (0x10000ul > l_dwCh) + { + if (4 <= l_iLength) + { + *o_pDst = (tACHAR)(0xE0ul | ((l_dwCh >> 12) & 0x0Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 6) & 0x3Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 0) & 0x3Ful)); o_pDst ++; + l_iLength -= 3; + } + else + { + break; + } + } + else if (0x200000ul > l_dwCh) + { + if (5 <= l_iLength) + { + *o_pDst = (tACHAR)(0xF0ul | ((l_dwCh >> 18) & 0x07ul)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 12) & 0x3Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 6) & 0x3Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 0) & 0x3Ful)); o_pDst ++; + l_iLength -= 4; + } + else + { + break; + } + } + else + { + *o_pDst = '?'; + o_pDst ++; + l_iLength -= 1; + } + + if (*i_pSrc) + { + ++i_pSrc; + } + else + { + break; + } + } + + *o_pDst = 0; + + return i_dwDst_Len - l_iLength; +}//Convert_UTF32_To_UTF8 + + +//////////////////////////////////////////////////////////////////////////////// +//Convert_UTF32_To_UTF16 (LE) +//Return - count of the used bytes, except trailing 0, if destination buffer +//size is not enough to store whole source string, result will be truncated +static UNUSED_FUNC tINT32 Convert_UTF32_To_UTF16(const tUINT32 *i_pSrc, + tWCHAR *o_pDst, + tUINT32 i_dwDst_Len + ) +{ + tINT32 l_iLength = i_dwDst_Len; + tUINT32 l_dwCh; + + if ( (NULL == i_pSrc) + || (NULL == o_pDst) + || (0 >= i_dwDst_Len) + ) + { + return -1; + } + + while ( ( 0ul != (*i_pSrc)) + && (3 <= l_iLength) + ) + { + if (*i_pSrc < 0x10000u) + { + *o_pDst++ = (tWCHAR)*i_pSrc; + l_iLength --; + } + else + { + l_dwCh = *i_pSrc - 0x10000u; + *o_pDst++ = (tWCHAR)(0xD800 | ((l_dwCh >> 10) & 0xFFFF)); + *o_pDst++ = (tWCHAR)(0xDC00 | ((l_dwCh & 0x3FF) & 0xFFFF)); + l_iLength -= 2; + } + + ++i_pSrc; + } + + *o_pDst = 0; + + return i_dwDst_Len - l_iLength; +}//Convert_UTF32_To_UTF16 + + +//////////////////////////////////////////////////////////////////////////////// +//Convert_UTF16_To_UTF8 (LE) +//Return - count of the used bytes, except trailing 0, if destination buffer +//size is not enough to store whole source string, result will be truncated +static UNUSED_FUNC tINT32 Convert_UTF16_To_UTF8(const tWCHAR *i_pSrc, + tACHAR *o_pDst, + tUINT32 i_dwDst_Len + ) +{ + tINT32 l_iLength = i_dwDst_Len; + tUINT32 l_dwCh = 0; + + if ( (NULL == i_pSrc) + || (NULL == o_pDst) + || (0 >= i_dwDst_Len) + ) + { + return -1; + } + + while ( ( 0ul != (*i_pSrc)) + && (2 <= l_iLength) + ) + { + l_dwCh = (tUINT16)(*i_pSrc); + + if ( (l_dwCh >= 0xD800ul) //processing surrogate pairs + && (l_dwCh <= 0xDFFFul) + ) + { + tUINT32 l_dwTrailing = (tUINT16)*(++i_pSrc); + if ( (0xDC00ul <= l_dwTrailing) + && (0xDFFFul >= l_dwTrailing) + ) + { + l_dwCh = 0x10000ul + (((l_dwCh & 0x3FFul) << 10) | (l_dwTrailing & 0x3FFul)); + } + else //unexpected + { + l_dwCh = '?'; + } + } + + if (0x80 > l_dwCh) + { + *o_pDst = (tACHAR)(l_dwCh & 0x7Ful); + o_pDst ++; + l_iLength--; + } + else if (0x800ul > l_dwCh) + { + if (3 <= l_iLength) + { + *o_pDst = (tACHAR)(0xC0ul | ((l_dwCh >> 6) & 0x1Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 0) & 0x3Ful)); o_pDst ++; + l_iLength -= 2; + } + else + { + break; + } + } + else if (0x10000ul > l_dwCh) + { + if (4 <= l_iLength) + { + *o_pDst = (tACHAR)(0xE0ul | ((l_dwCh >> 12) & 0x0Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 6) & 0x3Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 0) & 0x3Ful)); o_pDst ++; + l_iLength -= 3; + } + else + { + break; + } + } + else if (0x200000ul > l_dwCh) + { + if (5 <= l_iLength) + { + *o_pDst = (tACHAR)(0xF0ul | ((l_dwCh >> 18) & 0x07ul)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 12) & 0x3Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 6) & 0x3Ful)); o_pDst ++; + *o_pDst = (tACHAR)(0x80ul | ((l_dwCh >> 0) & 0x3Ful)); o_pDst ++; + l_iLength -= 4; + } + else + { + break; + } + } + else + { + *o_pDst = '?'; + o_pDst ++; + l_iLength -= 1; + } + + if (*i_pSrc) + { + ++i_pSrc; + } + else + { + break; + } + } + + *o_pDst = 0; + + return i_dwDst_Len - l_iLength; +}//Convert_UTF8_To_UTF16 + + +#endif //UTF_CONV_H diff --git a/p7lib/Shared/WString.h b/p7lib/Shared/WString.h new file mode 100644 index 0000000..6de0938 --- /dev/null +++ b/p7lib/Shared/WString.h @@ -0,0 +1,361 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//****************************************************************************** +// This header file provide simple string functionality * +//****************************************************************************** +#pragma once + +class CWString +{ + tXCHAR *m_pBuffer; + tUINT32 m_dwBuffer_Length; +public: + CWString(): + m_pBuffer(NULL) + ,m_dwBuffer_Length(0) + { + } + + CWString(const tXCHAR *i_pValue): + m_pBuffer(NULL) + ,m_dwBuffer_Length(0) + { + Set(i_pValue); + } + + ~CWString() + { + Remove(); + } + + tBOOL Realloc(tUINT32 i_dwLength) + { + tBOOL l_bResult = TRUE; + + if ( i_dwLength <= m_dwBuffer_Length ) + { + return l_bResult; + } + + tXCHAR *l_pBuffer = new tXCHAR[i_dwLength]; + if (l_pBuffer) + { + if (m_pBuffer) + { + PStrCpy(l_pBuffer, m_dwBuffer_Length, m_pBuffer); + Remove(); + } + else + { + l_pBuffer[0] = 0; + } + + m_dwBuffer_Length = i_dwLength; + m_pBuffer = l_pBuffer; + } + else + { + l_bResult = FALSE; + } + + return l_bResult; + } + + tBOOL Set(const tXCHAR *i_pValue) + { + tBOOL l_bResult = TRUE; + + if (NULL != i_pValue) + { + tUINT32 l_dwInput_Value_Length = (tUINT32)PStrLen(i_pValue); + if ( l_dwInput_Value_Length >= m_dwBuffer_Length ) + { + Remove(); + m_dwBuffer_Length = l_dwInput_Value_Length + 1; + m_pBuffer = new tXCHAR[m_dwBuffer_Length]; + } + + if (m_pBuffer) + { + PStrCpy(m_pBuffer, m_dwBuffer_Length, i_pValue); + } + else + { + l_bResult = FALSE; + Remove(); + } + } + else + { + Remove(); + } + + return l_bResult; + } + + // Example Append(3, L"Text1", L"Text2", L"Text3") + tBOOL Append(tUINT32 i_dwCount, ...) + { + tBOOL l_bResult = TRUE; + tUINT32 l_dwAppend_Length = 0; + tUINT32 l_dwString_Length = m_pBuffer ? (tUINT32)PStrLen(m_pBuffer) : 0; + + + //Parameters verification + tXCHAR *l_pItem = NULL; + tUINT32 l_dwIDX = 0; + va_list l_pVar_Args; + + if (l_bResult) + { + va_start(l_pVar_Args, i_dwCount); + + while (l_dwIDX < i_dwCount) + { + l_pItem = va_arg(l_pVar_Args, tXCHAR*); + if (l_pItem) + { + l_dwAppend_Length += (tUINT32)PStrLen(l_pItem); + } + + l_dwIDX ++; + } + + va_end(l_pVar_Args); + } + + if ( (l_bResult) && ( (l_dwAppend_Length + l_dwString_Length) >= m_dwBuffer_Length ) ) + { + m_dwBuffer_Length = l_dwAppend_Length + l_dwString_Length + 1; + tXCHAR *l_pTMP_Buffer = new tXCHAR[m_dwBuffer_Length]; + + if ( (l_pTMP_Buffer) && (m_pBuffer) && (l_dwString_Length) ) + { + PStrCpy(l_pTMP_Buffer, m_dwBuffer_Length, m_pBuffer); + } + + if (m_pBuffer) + { + delete [] m_pBuffer; + } + + m_pBuffer = l_pTMP_Buffer; + + if (NULL == m_pBuffer) + { + Remove(); + l_bResult = FALSE; + } + else if (0 >= l_dwString_Length) + { + m_pBuffer[0] = 0; + } + } + + if (l_bResult) + { + l_pItem = NULL; + l_dwIDX = 0; + + va_start(l_pVar_Args, i_dwCount); + + while (l_dwIDX < i_dwCount) + { + l_pItem = va_arg(l_pVar_Args, tXCHAR*); + if (l_pItem) + { + PStrCpy(m_pBuffer + l_dwString_Length, m_dwBuffer_Length - l_dwString_Length, l_pItem); + l_dwString_Length += (tUINT32)PStrLen(l_pItem); + } + + l_dwIDX ++; + } + + va_end(l_pVar_Args); + } + + return l_bResult; + } + + tXCHAR * Get() + { + return m_pBuffer; + } + + + tUINT32 Length() + { + return m_pBuffer ? (tUINT32)PStrLen(m_pBuffer) : 0; + } + + tUINT32 Max_Length() + { + return m_dwBuffer_Length; + } + + void Trim(tUINT32 i_dwLenght) + { + tUINT32 l_dwString_Length = m_pBuffer ? (tUINT32)PStrLen(m_pBuffer) : 0; + + if (i_dwLenght >= l_dwString_Length) + { + return; + } + + m_pBuffer[i_dwLenght] = 0; + } + + tINT32 Find(const tXCHAR *i_pSub, tBOOL i_bCase_Sens = FALSE) + { + if ( (NULL == i_pSub) + || (NULL == m_pBuffer) + ) + { + return -1; + } + + size_t l_dwSub_Len = PStrLen(i_pSub); + size_t l_dwStr_Len = PStrLen(m_pBuffer); + + if (FALSE == i_bCase_Sens) + { + for (size_t l_dwI = 0; l_dwI <= (l_dwStr_Len - l_dwSub_Len); l_dwI++) + { + if (0 == PStrNiCmp(m_pBuffer + l_dwI, i_pSub, l_dwSub_Len)) + { + return (int)l_dwI; + } + } + } + else + { + for (size_t l_dwI = 0; l_dwI <= (l_dwStr_Len - l_dwSub_Len); l_dwI++) + { + if (0 == PStrNCmp(m_pBuffer + l_dwI, i_pSub, l_dwSub_Len)) + { + return (int)l_dwI; + } + } + } + + return -1; + } + + + template + static tBOOL Str2Hex(const tXCHAR *i_pHex, size_t i_szCount, ValType &o_rVal) + { + tBOOL l_bReturn = TRUE; + o_rVal = 0; + + + if (!i_pHex) + { + return FALSE; + } + + while (i_szCount--) + { + if ((TM('0') <= (*i_pHex)) && (TM('9') >= (*i_pHex))) + { + o_rVal = (o_rVal << 4) + ((*i_pHex) - TM('0')); + } + else if ((TM('A') <= (*i_pHex)) && (TM('F') >= (*i_pHex))) + { + o_rVal = (o_rVal << 4) + ((*i_pHex) - TM('A') + 10); + } + else if ((TM('a') <= (*i_pHex)) && (TM('f') >= (*i_pHex))) + { + o_rVal = (o_rVal << 4) + ((*i_pHex) - TM('a') + 10); + } + else if (0 == (*i_pHex)) + { + break; + } + else + { + l_bReturn = FALSE; + break; + } + + i_pHex++; + } + + return l_bReturn; + } + + static tBOOL ScanGuid(const tXCHAR *i_pGuidText, GUID &o_rGUID) + { + if ( (!i_pGuidText) + || (TM('{')!= *i_pGuidText) + ) + { + return FALSE; + } + + i_pGuidText++; + + if (!CWString::Str2Hex(i_pGuidText, 8, (tUINT32&)o_rGUID.Data1)) return FALSE; + i_pGuidText += 9; + + if (!CWString::Str2Hex(i_pGuidText, 4, (tUINT16&)o_rGUID.Data2)) return FALSE; + i_pGuidText += 5; + + if (!CWString::Str2Hex(i_pGuidText, 4, (tUINT16&)o_rGUID.Data3)) return FALSE; + i_pGuidText += 5; + + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[0])) return FALSE; + i_pGuidText += 2; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[1])) return FALSE; + i_pGuidText += 3; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[2])) return FALSE; + i_pGuidText += 2; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[3])) return FALSE; + i_pGuidText += 2; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[4])) return FALSE; + i_pGuidText += 2; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[5])) return FALSE; + i_pGuidText += 2; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[6])) return FALSE; + i_pGuidText += 2; + if (!CWString::Str2Hex(i_pGuidText, 2, (tUINT8&)o_rGUID.Data4[7])) return FALSE; + i_pGuidText += 2; + + if (TM('}') != *i_pGuidText) + { + return FALSE; + } + + return TRUE; + } + + +private: + void Remove() + { + if (m_pBuffer) + { + delete [] m_pBuffer; + m_pBuffer = NULL; + } + + m_dwBuffer_Length = 0; + } + +}; diff --git a/p7lib/Sources/CMakeLists.txt b/p7lib/Sources/CMakeLists.txt new file mode 100644 index 0000000..8bebc21 --- /dev/null +++ b/p7lib/Sources/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +project(p7) + +include_directories(${PATH_SHARED}) +include_directories(${PATH_SHARED_PLATFORM}) +include_directories(${PATH_P7_API}) + +if(WIN32) + set(P7_PLATFORM_LIBS Ws2_32) +elseif(UNIX) + set(P7_PLATFORM_LIBS rt pthread) +else() + message(FATAL_ERROR "${PROJECT_NAME}: Platform not supported") +endif() + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} P7_SOURCES) + +add_library(${PROJECT_NAME} STATIC ${P7_SOURCES}) +target_link_libraries(${PROJECT_NAME} PUBLIC ${P7_PLATFORM_LIBS}) + +if(P7_BUILD_SHARED) + add_library(${PROJECT_NAME}-shared SHARED ${P7_SOURCES}) + target_link_libraries(${PROJECT_NAME}-shared ${P7_PLATFORM_LIBS}) +endif() + +set_property(TARGET ${PROJECT_NAME} PROPERTY POSITION_INDEPENDENT_CODE ON) + +if(P7_BUILD_SHARED) + set_property(TARGET ${PROJECT_NAME}-shared PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() + + +target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../Headers/") +if(P7_BUILD_SHARED) + target_include_directories(${PROJECT_NAME}-shared PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../Headers/") +endif() + +target_include_directories(${PROJECT_NAME} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/../Headers/") +target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../Shared/") + +if(WIN32) + target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../Shared/Platforms/Windows_x86/") +elseif(UNIX) + target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../Shared/Platforms/Linux_x86/") +endif() + +install(TARGETS ${PROJECT_NAME} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + ) + +if(P7_BUILD_SHARED) + install(TARGETS ${PROJECT_NAME}-shared + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin) +endif() + +if(COMMAND set_ide_folder) + set_ide_folder(${PROJECT_NAME}) + if(P7_BUILD_SHARED) + set_ide_folder(${PROJECT_NAME}-shared) + endif() +endif() diff --git a/p7lib/Sources/CRC32.cpp b/p7lib/Sources/CRC32.cpp new file mode 100644 index 0000000..b79ef82 --- /dev/null +++ b/p7lib/Sources/CRC32.cpp @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#include + +#include "GTypes.h" diff --git a/p7lib/Sources/ClBaical.cpp b/p7lib/Sources/ClBaical.cpp new file mode 100644 index 0000000..e269251 --- /dev/null +++ b/p7lib/Sources/ClBaical.cpp @@ -0,0 +1,1950 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to baical server / +// over UDP / +//////////////////////////////////////////////////////////////////////////////// + +#include "CommonClient.h" +#include "ClBaical.h" + + +#define COMMUNICATION_THREAD_IDLE_TIMEOUT (5) +#define COMMUNICATION_THREAD_EXIT_TIMEOUT (5000) +#define COMMUNICATION_RESPONSE_TIMEOUT (100) +#define COMMUNICATION_DATA_SEGMENT_MAX_DURATION (750) +#define COMMUNICATION_IDLE_TIMEOUT (1000) +#define COMMUNICATION_LOSSES_MAX (60) //percents + +#define COMMUNICATION_MAX_DELIVERY_FAILS (10) +#define SOCKET_RECEIVE_RESPONSE_TIMEOUT (10) + +#define CONNECTION_SIGNAL (MEVENT_SIGNAL_0) + +#define THREAD_EXIT_SIGNAL (MEVENT_SIGNAL_0) +#define THREAD_DATA_SIGNAL (MEVENT_SIGNAL_0 + 1) + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//CClBaical +CClBaical::CClBaical(tXCHAR **i_pArgs, tINT32 i_iCount) + : CClient(IP7_Client::eBaical, i_pArgs, i_iCount) + , m_lReject_Mem(0) + , m_lReject_Con(0) + , m_lReject_Int(0) + + , m_bIs_Winsock(FALSE) + , m_pSocket(NULL) + , m_wClient_ID(0xFFFF) + , m_pBPool(NULL) + + , m_pData_Wnd(NULL) + , m_pData_Wnd_Cell(NULL) + , m_bData_Wnd_Fixed(FALSE) + , m_dwData_Wnd_Max_Count(0) + , m_dwData_Wnd_Size(0) + , m_dwData_Wnd_TimeStamp(0) + , m_dwData_Wnd_First_ID(TPACKET_MAX_ID + 1) + , m_dwData_Wnd_Last_ID(TPACKET_MAX_ID + 1) + , m_bData_Resending(FALSE) + + , m_dwDelivery_Fails(0) + , m_bIs_Response_Waiting(FALSE) + + , m_pData_Queue_Out(NULL) + , m_pData_Queue_In(NULL) + + , m_dwLast_Packet_ID(0) + , m_dwServiceTimeStamp(0) + + , m_dwExit_TimeOut(COMMUNICATION_THREAD_EXIT_TIMEOUT) + + , m_pPacket_Control(NULL) + , m_bBig_Endian(FALSE) + + , m_bConn_Event(TRUE) + , m_bComm_Thread(FALSE) + , m_hComm_Thread(0) //NULL + , m_bChnl_Thread(FALSE) + , m_hChnl_Thread(0) //NULL + + , m_bLocalHost(FALSE) + , m_bExtension(FALSE) + + , m_pHdrUsrData(NULL) + , m_pHdrUsrPacket(NULL) + , m_uHdrUsrSize(0) + , m_uHdrUsrChannel(USER_PACKET_CHANNEL_ID_MAX_SIZE) +{ + memset(&m_hCS_Data_Out, 0, sizeof(m_hCS_Data_Out)); + memset(&m_hCS_Data_In, 0, sizeof(m_hCS_Data_In)); + + //1. base init + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Base(i_pArgs, i_iCount); + } + + //2. initialize network layer and sockets + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Sockets(i_pArgs, i_iCount); + } + + //3. Initialize Pool + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Pool(i_pArgs, i_iCount); + } + + //4. Initialize variables + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Members(i_pArgs, i_iCount); + } + + //5. Initialize crash handler + if (ECLIENT_STATUS_OK == m_eStatus) + { + Init_Crash_Handler(i_pArgs, i_iCount); + } + +}//CClBaical + + +//////////////////////////////////////////////////////////////////////////////// +//~CClBaical +CClBaical::~CClBaical() +{ + Uninit_Crash_Handler(); + + Close(); + + CClient::Unshare(); + + if (m_pData_Queue_Out) + { + pAList_Cell l_pElement = NULL; + + while ((l_pElement = m_pData_Queue_Out->Get_First())) + { + CTPacket *l_pPacket = m_pData_Queue_Out->Get_Data(l_pElement); + m_pData_Queue_Out->Del(l_pElement, FALSE); + m_pBPool->Push_Buffer(l_pPacket); + } + + m_pData_Queue_Out->Clear(TRUE); + delete m_pData_Queue_Out; + m_pData_Queue_Out = NULL; + } + + + if (m_pData_Queue_In) + { + pAList_Cell l_pElement = NULL; + + while ((l_pElement = m_pData_Queue_In->Get_First())) + { + CTPacket *l_pPacket = m_pData_Queue_In->Get_Data(l_pElement); + m_pData_Queue_In->Del(l_pElement, FALSE); + m_pBPool->Push_Buffer(l_pPacket); + } + + m_pData_Queue_In->Clear(TRUE); + delete m_pData_Queue_In; + m_pData_Queue_In = NULL; + } + + + if (m_pData_Wnd) + { + pAList_Cell l_pElement = NULL; + + while ((l_pElement = m_pData_Wnd->Get_First())) + { + CTPacket *l_pPacket = m_pData_Wnd->Get_Data(l_pElement); + m_pData_Wnd->Del(l_pElement, FALSE); + m_pBPool->Push_Buffer(l_pPacket); + } + + m_pData_Wnd->Clear(TRUE); + delete m_pData_Wnd; + m_pData_Wnd = NULL; + } + + //stop sockets + if (m_bIs_Winsock) + { + WSA_UnInit(); + } + + if (m_pSocket) + { + delete m_pSocket; + m_pSocket = NULL; + } + + //clear pool + if (m_pBPool) + { + delete m_pBPool; + m_pBPool = NULL; + } + + LOCK_DESTROY(m_hCS_Data_Out); + LOCK_DESTROY(m_hCS_Data_In); +} //~CClBaical + +//////////////////////////////////////////////////////////////////////////////// +//Init_Base +eClient_Status CClBaical::Init_Base(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + UNUSED_ARG(i_pArgs); + UNUSED_ARG(i_iCount); + + return l_eReturn; +}//Init_Base + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Sockets +eClient_Status CClBaical::Init_Sockets(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + + if (FALSE == WSA_Init()) + { + P7_Set_Last_Error(eP7_Error_Network); + + JOURNAL_CRITICAL(m_pLog, + TM("Socket initialization fail !")); + + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + else + { + m_bIs_Winsock = TRUE; + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + tXCHAR *l_pAddr = NULL; + tXCHAR *l_pPort = NULL; + + tADDR_INFO *l_pInfo = NULL; + tADDR_INFO *l_pNext = NULL; + tADDR_INFO l_tHint; + + memset(&l_tHint, 0, sizeof(l_tHint)); + + l_pAddr = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_ADDRESS); + if (NULL == l_pAddr) + { + l_pAddr = (tXCHAR*)TM("127.0.0.1"); + } + + l_pPort = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_PORT); + + if (NULL == l_pPort) + { + l_pPort = (tXCHAR*)TM("9009"); + } + + + if ( (0 == PStrICmp(l_pAddr, TM("127.0.0.1"))) + || (0 == PStrICmp(l_pAddr, TM("::1"))) + ) + { + m_bLocalHost = TRUE; + } + + l_tHint.ai_family = AF_UNSPEC; //AF_INET; + l_tHint.ai_socktype = SOCK_DGRAM; + l_tHint.ai_protocol = IPPROTO_UDP; + + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + + //http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx + //http://linux.die.net/man/3/getaddrinfo + if (0 == GET_ADDR_INFO(l_pAddr, l_pPort, &l_tHint, &l_pInfo)) + { + for(l_pNext = l_pInfo; l_pNext != NULL ;l_pNext=l_pNext->ai_next) + { + if ( ( (AF_INET == l_pNext->ai_family) + || (AF_INET6 == l_pNext->ai_family) + ) + && (SOCK_DGRAM == l_pNext->ai_socktype) + && (IPPROTO_UDP == l_pNext->ai_protocol) + ) + { + m_pSocket = new CUDP_Socket(m_pLog, + (sockaddr*) l_pNext->ai_addr, + FALSE); + if (m_pSocket) + { + if (m_pSocket->Initialized()) + { + l_eReturn = ECLIENT_STATUS_OK; + break; + } + else + { + delete m_pSocket; + m_pSocket = NULL; + } + } + } + } + } //if (0 == GetAddrInfoW + + if (l_pInfo) + { + FREE_ADDR_INFO(l_pInfo); + l_pInfo = NULL; + } + + if (ECLIENT_STATUS_OK != l_eReturn) + { + P7_Set_Last_Error(eP7_Error_Network); + } + }//if (ECLIENT_STATUS_OK == l_eReturn) + + return l_eReturn; +}//Init_Sockets + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Pool +eClient_Status CClBaical::Init_Pool(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + tXCHAR *l_pArg_Value = NULL; + tUINT32 l_dwMax_Memory = 0x100000; //1mb by default + tUINT32 l_dwPacket_Size = TPACKET_DEF_SIZE; + + //////////////////////////////////////////////////////////////////////////// + //packet size + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_PACKET_BAICAL_SIZE); + if (l_pArg_Value) + { + l_dwPacket_Size = (tUINT32)PStrToInt(l_pArg_Value); + + if (TPACKET_MIN_SIZE > l_dwPacket_Size) + { + l_dwPacket_Size = TPACKET_MIN_SIZE; + } + else if (TPACKET_MAX_SIZE < l_dwPacket_Size) + { + l_dwPacket_Size = TPACKET_MAX_SIZE; + } + } + + if (m_bLocalHost) + { + l_dwPacket_Size = TPACKET_MAX_SIZE; + } + + //////////////////////////////////////////////////////////////////////////// + //pool size + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_POOL_SIZE); + if (l_pArg_Value) + { + l_dwMax_Memory = 1024 * (tUINT32)PStrToInt(l_pArg_Value); + + if (16384 > l_dwMax_Memory) + { + l_dwMax_Memory = 16384; + } + } + + //check that memory is enough to store 20 packets + if (l_dwMax_Memory < (l_dwPacket_Size * 20)) + { + l_dwMax_Memory = l_dwPacket_Size * 20; + + JOURNAL_WARNING(m_pLog, + TM("Pool size is not enought to store 20 packets, enlarge up to %d"), + l_dwMax_Memory + ); + } + + + //////////////////////////////////////////////////////////////////////////// + //window size + + //size of the transmission window in packets. Sometimes is useful to manage it + //if server aggressively loose incoming packets + //Min = 1 + //max = ((pool size / packet size) / 2) + + //here is possible maximal window length + tUINT32 l_uWnd_Max_Total = (SERVER_REPORT_SIZE - SERVER_REPORT_HEADER_SIZE) * 8; + //if window size is more than half of all memory we resize the window length + tUINT32 l_uWnd_Max_Mem = (l_dwMax_Memory / l_dwPacket_Size) / 2; + //if window size is more than socket buffer size, truncate to it + tUINT32 l_uWnd_Max_Net = (m_pSocket->GetSendBufferSize() / l_dwPacket_Size) - 1; + tUINT32 l_uWnd_Max_Usr = l_uWnd_Max_Total; + + + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_WINDOW_BAICAL_SIZE); + if (l_pArg_Value) + { + l_uWnd_Max_Usr = (tUINT32)PStrToInt(l_pArg_Value); + + if (1 > l_uWnd_Max_Usr) + { + l_uWnd_Max_Usr = 1; + } + + m_bData_Wnd_Fixed = TRUE; + } + + //select minimum window size + m_dwData_Wnd_Max_Count = l_uWnd_Max_Total; + if (l_uWnd_Max_Mem < m_dwData_Wnd_Max_Count) m_dwData_Wnd_Max_Count = l_uWnd_Max_Mem; + if (l_uWnd_Max_Net < m_dwData_Wnd_Max_Count) m_dwData_Wnd_Max_Count = l_uWnd_Max_Net; + if (l_uWnd_Max_Usr < m_dwData_Wnd_Max_Count) m_dwData_Wnd_Max_Count = l_uWnd_Max_Usr; + + + + //////////////////////////////////////////////////////////////////////////// + //initialize pool + m_pBPool = new CBuffers_Pool(m_pLog, + l_dwMax_Memory / 10, //10% + l_dwMax_Memory, //100% + l_dwPacket_Size, + 0 + ); + + if ( (NULL != m_pBPool) + && (FALSE == m_pBPool->Get_Initialized()) + ) + { + JOURNAL_CRITICAL(m_pLog, TM("Pool initialization failed")); + + delete m_pBPool; + m_pBPool = NULL; + } + + JOURNAL_INFO(m_pLog, + TM("Pool: Max memory = %d, Packet size = %d, Window length = %d"), + l_dwMax_Memory, + l_dwPacket_Size, + m_dwData_Wnd_Max_Count + ); + + if (NULL == m_pBPool) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + } + + return (NULL != m_pBPool) ? ECLIENT_STATUS_OK : ECLIENT_STATUS_INTERNAL_ERROR; +}//Init_Pool + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Members +eClient_Status CClBaical::Init_Members(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tXCHAR *l_pArg_Value = NULL; + + if (ECLIENT_STATUS_OK == l_eReturn) + { + LOCK_CREATE(m_hCS_Data_Out); + LOCK_CREATE(m_hCS_Data_In); + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + m_pData_Queue_Out = new CBList(); + if (NULL == m_pData_Queue_Out) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_CRITICAL(m_pLog, TM("Data queue [out] initialization failed")); + } + } + + + if (ECLIENT_STATUS_OK == l_eReturn) + { + m_pData_Queue_In = new CBList(); + if (NULL == m_pData_Queue_In) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_CRITICAL(m_pLog, TM("Data queue [in] initialization failed")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + m_pData_Wnd = new CBList(); + if (NULL == m_pData_Wnd) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_CRITICAL(m_pLog, TM("Data lagoon initialization failed")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + tUINT32 l_dwHTime = 0; + tUINT32 l_dwLTime = 0; + tWCHAR l_pProc_Name[TPACKET_PROCESS_NAME_MAX_LEN]; + tUINT32 l_dwEndian = 0x1; + tUINT8 l_bLittleE = *(tUINT8*)&l_dwEndian; + + l_pProc_Name[0] = 0; + + CProc::Get_Process_Time(&l_dwHTime, &l_dwLTime); + + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_NAME); + if (!l_pArg_Value) + { + CProc::Get_Process_Name(l_pProc_Name, LENGTH(l_pProc_Name)); + } + else + { + #ifdef UTF8_ENCODING + Convert_UTF8_To_UTF16((const char*)l_pArg_Value, + l_pProc_Name, + LENGTH(l_pProc_Name) + ); + #else + PStrCpy((tXCHAR*)l_pProc_Name, LENGTH(l_pProc_Name), l_pArg_Value); + #endif + } + + m_cPacket_Hello.Fill(CLIENT_PROTOCOL_VERSION, + (tUINT16)m_pBPool->Get_Buffer_Size(), + CProc::Get_Process_ID(), + l_dwHTime, + l_dwLTime, + l_pProc_Name + ); + + Inc_Packet_ID(&m_dwLast_Packet_ID); + + if (!l_bLittleE) + { + m_bBig_Endian = TRUE; + m_cPacket_Hello.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN); + m_cPacket_Data_Report.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN); + m_cPacket_Alive.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN); + m_cPacket_Bye.Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN); + } + + m_cPacket_Hello.Set_Flag(TPACKET_FLAG_EXTENSION); + + #if defined(GTX64) + m_cPacket_Hello.Set_Flag(TPACKET_FLAG_ARCH_64); + #endif + + m_cPacket_Hello.Finalize(m_dwLast_Packet_ID, m_wClient_ID); + + m_pPacket_Control = static_cast(&m_cPacket_Hello); + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_EXIT_TIMEOUT); + if (l_pArg_Value) + { + m_dwExit_TimeOut = PStrToInt(l_pArg_Value); + if (15 < m_dwExit_TimeOut) + { + m_dwExit_TimeOut = 15; + } + + m_dwExit_TimeOut *= 1000; + } + } + + //////////////////////////////////////////////////////////////////////////// + //threads initialization + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == m_cConn_Event.Init(1, EMEVENT_SINGLE_MANUAL)) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Connection event wasn't created !")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == m_cComm_Event.Init(1, EMEVENT_SINGLE_AUTO)) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == CThShell::Create(&Static_Comm_Routine, + this, + &m_hComm_Thread, + TM("P7:Comm") + ) + ) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Communication thread wasn't created !")); + } + else + { + m_bComm_Thread = TRUE; + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == m_cChnl_Event.Init(2, EMEVENT_SINGLE_AUTO, EMEVENT_MULTI)) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == CThShell::Create(&Static_Chnl_Routine, + this, + &m_hChnl_Thread, + TM("P7:Channel") + ) + ) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Channel thread wasn't created !")); + } + else + { + m_bChnl_Thread = TRUE; + } + } + + return l_eReturn; +}//Init_Members + + +//////////////////////////////////////////////////////////////////////////////// +//Inc_Packet_ID +void CClBaical::Inc_Packet_ID(tUINT32 * o_pPacketID) +{ + ++(*o_pPacketID); + if ( TPACKET_MAX_ID < (*o_pPacketID) ) + { + (*o_pPacketID) = 1; + } +}//Inc_Packet_ID + + +//////////////////////////////////////////////////////////////////////////////// +//Process_Incoming_Packet +tBOOL CClBaical::Process_Incoming_Packet(CTPacket *i_pPacket) +{ + tBOOL l_bResult = TRUE; + + if (NULL == i_pPacket) + { + l_bResult = FALSE; + } + + //check packet integrity + if ( (l_bResult) + && (TRUE == i_pPacket->Is_Damaged()) + ) + { + JOURNAL_ERROR(m_pLog, + TM("Packet is corrupted (CRC32) Packet ID=%d, Size=%d, Type=%d, CRC=0x%X"), + i_pPacket->Get_ID(), + i_pPacket->Get_Size(), + i_pPacket->Get_Type(), + i_pPacket->Get_Crc() + ); + + m_bIs_Response_Waiting = FALSE; + m_dwDelivery_Fails ++; + l_bResult = FALSE; + } + + if (FALSE == m_bIs_Response_Waiting) + { + l_bResult = FALSE; + JOURNAL_WARNING(m_pLog, + TM("Drop packet, ID = %d"), + i_pPacket->Get_ID() + ); + } + + if (l_bResult) + { + m_wClient_ID = i_pPacket->Get_Client_ID(); + } + + if (l_bResult) + { + eTPacket_Type l_eType = i_pPacket->Get_Type(); + if (ETPT_ACKNOWLEDGMENT == l_eType) + { + CTPAcknowledgment l_cServerResponse(i_pPacket); + + //verify that response source ID is equal to control ID + if ( (m_pPacket_Control) + && (l_cServerResponse.Get_Source_ID() == m_pPacket_Control->Get_ID()) + ) + { + m_bIs_Response_Waiting = FALSE; + m_pData_Wnd_Cell = NULL; + m_dwDelivery_Fails = 0; + + if (l_cServerResponse.Get_Result()) + { + if (ETPT_CLIENT_HELLO == m_pPacket_Control->Get_Type()) + { + LOCK_ENTER(m_hCS_Data_In); + if (TPACKET_FLAG_EXTENSION & i_pPacket->Get_Flags()) + { + m_bExtension = TRUE; + } + else + { + m_bExtension = FALSE; + } + LOCK_EXIT(m_hCS_Data_In); + } + + //if this is response to data report packet ... + if (ETPT_CLIENT_DATA_REPORT == m_pPacket_Control->Get_Type()) + { + pAList_Cell l_pElement = NULL; + while ((l_pElement = m_pData_Wnd->Get_First()) != NULL) + { + CTPacket * l_pPacket = m_pData_Wnd->Get_Data(l_pElement); + m_pData_Wnd->Del(l_pElement, FALSE); + m_pBPool->Push_Buffer(l_pPacket); + } + + m_dwData_Wnd_First_ID = TPACKET_MAX_ID + 1; + m_dwData_Wnd_Last_ID = TPACKET_MAX_ID + 1; + m_dwData_Wnd_Size = 0; + m_bData_Resending = FALSE; + } + else if (m_bConn_Event) + { + m_bConn_Event = FALSE; + m_cConn_Event.Set(CONNECTION_SIGNAL); + } + + //control packet is local class packet + //it is not necessary to return it to pool + m_pPacket_Control = NULL; + } + else //server set this flag to 0 when it not recognize this client + { + Reset_Connetion(); + } + + if (TPACKET_FLAG_EXTENSION & i_pPacket->Get_Flags()) + { + Parse_Extensions(l_cServerResponse.Get_Buffer() + ACKNOWLEDGMENT_SIZE, + (size_t)l_cServerResponse.Get_Size() - ACKNOWLEDGMENT_SIZE + ); + } + + if (TPACKET_FLAG_EXTRA_DATA & i_pPacket->Get_Flags()) + { + LOCK_ENTER(m_hCS_Data_In); + m_pData_Queue_In->Add_After(m_pData_Queue_In->Get_Last(), i_pPacket); + LOCK_EXIT(m_hCS_Data_In); + + m_cChnl_Event.Set(THREAD_DATA_SIGNAL); + + i_pPacket = NULL; + } + } + } + else if (ETPT_SERVER_DATA_REPORT == l_eType) + { + CTPData_Window_Report l_cServerReport(i_pPacket); + + if (l_cServerReport.Get_Source_ID() == m_pPacket_Control->Get_ID() ) + { + tUINT32 l_dwTotal = m_pData_Wnd->Count(); + m_bIs_Response_Waiting = FALSE; + m_pData_Wnd_Cell = NULL; + m_bData_Resending = TRUE; + + pAList_Cell l_pEl = m_pData_Wnd->Get_First(); + pAList_Cell l_pEl_Exch = NULL; + while (l_pEl) + { + CTPacket *l_pPacket = m_pData_Wnd->Get_Data(l_pEl); + + l_pEl_Exch = m_pData_Wnd->Get_Next(l_pEl); + + if (FALSE == l_cServerReport.Is_ID(m_cPacket_Data_Report.Get_First_ID(), + l_pPacket->Get_ID() + ) + ) + { + m_pData_Wnd->Del(l_pEl, FALSE); + m_pBPool->Push_Buffer(l_pPacket); + } + + l_pEl = l_pEl_Exch; + } + + if (m_pData_Wnd->Count()) + { + JOURNAL_ERROR(m_pLog, + TM("Server report: count of lost packets: %d, total: %d"), + m_pData_Wnd->Count(), + l_dwTotal + ); + + if ( (!m_bData_Wnd_Fixed) + && ((m_pData_Wnd->Count() * 100 / l_dwTotal) >= COMMUNICATION_LOSSES_MAX) + ) + { + JOURNAL_ERROR(m_pLog, + TM("Recalculate transmission window due to network losses, new length: %d"), + m_dwData_Wnd_Max_Count + ); + m_dwData_Wnd_Max_Count = (l_dwTotal - m_pData_Wnd->Count()); + } + + } + else + { + m_bData_Resending = FALSE; + JOURNAL_ERROR(m_pLog, + TM("Server report: empty report is received !") + ); + } + + m_pPacket_Control = NULL; + } + } // else if (ETPT_SERVER_DATA_REPORT == l_eType) + }//if (l_bResult) + + if (i_pPacket) + { + m_pBPool->Push_Buffer(i_pPacket); + } + + return l_bResult; +}//Process_Incoming_Packet + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Delivered_Packet +CTPacket * CClBaical::Get_Delivered_Packet() +{ + CTPacket *l_pReturn = NULL; + tBOOL l_bFilled = FALSE; + + if (TRUE == m_bIs_Response_Waiting) + { + //if timeout is exceed we flush flag of waiting and resend the same control packet + if (CTicks::Difference(GetTickCount(), m_dwServiceTimeStamp) >= COMMUNICATION_RESPONSE_TIMEOUT) + { + JOURNAL_ERROR(m_pLog, + TM("Server Response waiting timeout. Resending ...") + ); + + m_bIs_Response_Waiting = FALSE; + m_dwDelivery_Fails ++; + } + else + { + l_bFilled = TRUE; + } + } + + //Do we have control packet + if ( (FALSE == l_bFilled) + && (m_pPacket_Control) + ) + { + m_dwServiceTimeStamp = GetTickCount(); + l_bFilled = TRUE; + m_bIs_Response_Waiting = TRUE; + l_pReturn = m_pPacket_Control; + } + + //if we sending data packets and some limits are exceed .... + //we send report packet + if ( (FALSE == l_bFilled) + && (FALSE == m_bData_Resending) + && (m_pData_Wnd->Count()) + ) + { + if ( (CTicks::Difference(GetTickCount(), m_dwData_Wnd_TimeStamp) >= COMMUNICATION_DATA_SEGMENT_MAX_DURATION) + || (m_dwData_Wnd_Max_Count <= m_pData_Wnd->Count()) + ) + { + l_pReturn = Create_Data_Wnd_Report(); + l_bFilled = TRUE; + } + } //if ((FALSE == l_bFilled) && (0 == m_dwDelivery_Fails)) + + + if (FALSE == l_bFilled) + { + if (FALSE == m_bData_Resending) + { + l_pReturn = Pull_Firt_Data_Packet(); + if (l_pReturn) + { + //if data window is empty - this is first data packet + //we need to check ID for overflow, to be sure that all ID + //inside data window will be sequential + if ( (0 == m_pData_Wnd->Count()) && + ((m_dwLast_Packet_ID + m_dwData_Wnd_Max_Count + 128) >= TPACKET_MAX_ID) + ) + { + m_dwLast_Packet_ID = 1; + } + else + { + Inc_Packet_ID(&m_dwLast_Packet_ID); + } + + //we store time when we start sending data + if (0 == m_pData_Wnd->Count()) + { + m_dwData_Wnd_TimeStamp = GetTickCount(); + + //JOURNAL_DEBUG(m_pLog, + // L"Start sending data"); + } + + if (m_bBig_Endian) + { + l_pReturn->Set_Flag(TPACKET_FLAG_BIG_ENDIAN_CLN); + } + + l_pReturn->Finalize(m_dwLast_Packet_ID, m_wClient_ID); + + m_dwData_Wnd_Size += l_pReturn->Get_Size(); + m_pData_Wnd->Add_After(m_pData_Wnd->Get_Last(), l_pReturn); + m_dwServiceTimeStamp = GetTickCount(); + l_bFilled = TRUE; + } + else if (m_pData_Wnd->Count()) + { + l_pReturn = Create_Data_Wnd_Report(); + l_bFilled = TRUE; + } + }//if (FALSE == m_bData_Resending) + else if (m_pData_Wnd->Count()) + { + //if redeliver all packets from data window + if (m_pData_Wnd_Cell == m_pData_Wnd->Get_Last()) + { + if ( (TPACKET_MAX_ID > m_dwData_Wnd_First_ID) + && (TPACKET_MAX_ID > m_dwData_Wnd_Last_ID) + ) + { + l_pReturn = &m_cPacket_Data_Report; + m_pPacket_Control = &m_cPacket_Data_Report; + + Inc_Packet_ID(&m_dwLast_Packet_ID); + + m_cPacket_Data_Report.Fill(m_dwData_Wnd_First_ID, m_dwData_Wnd_Last_ID); + m_cPacket_Data_Report.Finalize(m_dwLast_Packet_ID, m_wClient_ID); + + m_bIs_Response_Waiting = TRUE; + m_dwServiceTimeStamp = GetTickCount(); + m_pData_Wnd_Cell = NULL; + l_bFilled = TRUE; + } + } + else + { + m_pData_Wnd_Cell = m_pData_Wnd->Get_Next(m_pData_Wnd_Cell); + l_pReturn = m_pData_Wnd->Get_Data(m_pData_Wnd_Cell); + m_dwServiceTimeStamp = GetTickCount(); + l_bFilled = TRUE; + } + }//else if (m_pData_Wnd->Count()) + + } //if (FALSE == l_bFilled) + + + //nothing to send, let's sent alive packet. + if ( (FALSE == l_bFilled) + && (0 == m_pData_Wnd->Count()) + && (CTicks::Difference(GetTickCount(), m_dwServiceTimeStamp) >= COMMUNICATION_IDLE_TIMEOUT) + ) + { + l_pReturn = &m_cPacket_Alive; + Inc_Packet_ID(&m_dwLast_Packet_ID); + l_pReturn->Finalize(m_dwLast_Packet_ID, m_wClient_ID); + m_bIs_Response_Waiting = TRUE; + m_dwServiceTimeStamp = GetTickCount(); + l_bFilled = TRUE; + m_pPacket_Control = l_pReturn; + } + + return l_pReturn; +}//Get_Delivered_Packet + + +//////////////////////////////////////////////////////////////////////////////// +//Is_Ready_To_Exit +tBOOL CClBaical::Is_Ready_To_Exit() +{ + tBOOL l_bResult = TRUE; + if (FALSE == m_bConnected) + { + return TRUE; + } + + LOCK_ENTER(m_hCS_Data_Out); + + l_bResult = ( (0 == m_pData_Queue_Out->Count()) && (0 == m_pData_Wnd->Count()) ); + + LOCK_EXIT(m_hCS_Data_Out); + + return l_bResult; +}//Is_Ready_To_Exit + + +//////////////////////////////////////////////////////////////////////////////// +//Set_Connected +void CClBaical::Set_Connected(tBOOL i_bConnected) +{ + if (i_bConnected == m_bConnected) + { + return; + } + + //////////////////////////////////////////////////////////////////////////// + //update internal state + LOCK_ENTER(m_hCS); + m_bConnected = i_bConnected; + + if (i_bConnected) + { + m_dwConnection_Resets ++; + } + LOCK_EXIT(m_hCS); + // + //////////////////////////////////////////////////////////////////////////// + + JOURNAL_ERROR(m_pLog, + TM("Set connection : %s"), + (m_bConnected) ? TM("ON") : TM("OFF") + ); +}//Set_Connection_Status + + +//////////////////////////////////////////////////////////////////////////////// +//Reset_Connetion +void CClBaical::Reset_Connetion() +{ + CTPacket * l_pPacket = NULL; + + JOURNAL_WARNING(m_pLog, TM("Reset Connection")); + + if (m_pPacket_Control) + { + m_pPacket_Control = NULL; + } + + //m_dwDelivery_Fails = 0; + m_bIs_Response_Waiting = FALSE; + m_pData_Wnd_Cell = NULL; + m_dwData_Wnd_First_ID = TPACKET_MAX_ID + 1; + m_dwData_Wnd_Last_ID = TPACKET_MAX_ID + 1; + m_dwData_Wnd_Size = 0; + m_bData_Resending = FALSE; + + pAList_Cell l_pElement = NULL; + while ((l_pElement = m_pData_Wnd->Get_First()) != NULL) + { + l_pPacket = m_pData_Wnd->Get_Data(l_pElement); + m_pData_Wnd->Del(l_pElement, FALSE); + m_pBPool->Push_Buffer(l_pPacket); + } + + //shutdown all connections for clients and update reset counter + Update_Channels_Status(FALSE, m_dwConnection_Resets + 1); + + //protect list against user calls + LOCK_ENTER(m_hCS); + + while ((l_pPacket = Pull_Firt_Data_Packet()) != NULL) + { + m_pBPool->Push_Buffer(l_pPacket); + } + + m_dwConnection_Resets ++; + + LOCK_EXIT(m_hCS); + + //if connection is established - inform all clients about it + if (m_bConnected) + { + LOCK_ENTER(m_hCS); + m_dwConnection_Resets ++; + LOCK_EXIT(m_hCS); + Update_Channels_Status(m_bConnected, m_dwConnection_Resets); + } + + Inc_Packet_ID(&m_dwLast_Packet_ID); + m_cPacket_Hello.Finalize(m_dwLast_Packet_ID, m_wClient_ID); + + m_pPacket_Control = static_cast(&m_cPacket_Hello); +}//Reset_Connetion + + +//////////////////////////////////////////////////////////////////////////////// +//RoutineCreate_Data_Wnd_Report +CTPacket * CClBaical::Create_Data_Wnd_Report() +{ + CTPacket *l_pResult = NULL; + + m_dwData_Wnd_First_ID = TPACKET_MAX_ID + 1; + m_dwData_Wnd_Last_ID = TPACKET_MAX_ID + 1; + + CTPacket *l_pLagoonPacket = m_pData_Wnd->Get_Data(m_pData_Wnd->Get_First()); + if (l_pLagoonPacket) + { + m_dwData_Wnd_First_ID = l_pLagoonPacket->Get_ID(); + } + + l_pLagoonPacket = m_pData_Wnd->Get_Data(m_pData_Wnd->Get_Last()); + if (l_pLagoonPacket) + { + m_dwData_Wnd_Last_ID = l_pLagoonPacket->Get_ID(); + } + + if ( (TPACKET_MAX_ID > m_dwData_Wnd_First_ID) + && (TPACKET_MAX_ID > m_dwData_Wnd_Last_ID) + ) + { + Inc_Packet_ID(&m_dwLast_Packet_ID); + m_cPacket_Data_Report.Fill(m_dwData_Wnd_First_ID, m_dwData_Wnd_Last_ID); + m_cPacket_Data_Report.Finalize(m_dwLast_Packet_ID, m_wClient_ID); + + l_pResult = &m_cPacket_Data_Report; + m_bIs_Response_Waiting = TRUE; + m_dwServiceTimeStamp = GetTickCount(); + m_pPacket_Control = l_pResult; + } + + return l_pResult; +}//RoutineCreate_Data_Wnd_Report + + +//////////////////////////////////////////////////////////////////////////////// +//Pull_Firt_Data_Packet +CTPacket *CClBaical::Pull_Firt_Data_Packet() +{ + CTPacket * l_pResult = NULL; + + LOCK_ENTER(m_hCS_Data_Out); + + pAList_Cell l_pElement = m_pData_Queue_Out->Get_First(); + if (l_pElement) + { + l_pResult = m_pData_Queue_Out->Get_Data(l_pElement); + m_pData_Queue_Out->Del(l_pElement, FALSE); + } + + if (m_pHdrUsrPacket == l_pResult) + { + m_pHdrUsrPacket = 0; + m_pHdrUsrData = 0; + m_uHdrUsrSize = 0; + m_uHdrUsrChannel = USER_PACKET_CHANNEL_ID_MAX_SIZE; + } + + LOCK_EXIT(m_hCS_Data_Out); + + return l_pResult; +}//Pull_Firt_Data_Packet + + +//////////////////////////////////////////////////////////////////////////////// +//Pull_Last_Data_Packet +CTPacket *CClBaical::Reuse_Data_Packet(CTPData &i_rData, tUINT32 i_uChannel_ID, tUINT32 i_uSize) +{ + CTPacket *l_pResult = NULL; + + LOCK_ENTER(m_hCS_Data_Out); + + pAList_Cell l_pElement = m_pData_Queue_Out->Get_Last(); + if (l_pElement) + { + l_pResult = m_pData_Queue_Out->Get_Data(l_pElement); + m_pData_Queue_Out->Del(l_pElement, FALSE); + } + + if ( (m_pHdrUsrPacket) + && (m_uHdrUsrChannel == i_uChannel_ID) + && ((i_uSize + m_uHdrUsrSize) <= CHANNEL_PACKETS_UNION_MAX_SIZE) + ) + { + m_uHdrUsrSize += i_uSize; + sH_User_Raw l_sHeader = { INIT_USER_HEADER(m_uHdrUsrSize, m_uHdrUsrChannel) }; + memcpy(m_pHdrUsrData, &l_sHeader, sizeof(l_sHeader)); + + if (l_pResult) + { + i_rData.Attach(l_pResult); + if (0 >= i_rData.Get_Tail_Size()) + { + i_rData.Detach(); + m_pData_Queue_Out->Add_After(m_pData_Queue_Out->Get_Last(), l_pResult); + l_pResult = m_pBPool->Pull_Buffer(); + i_rData.Attach(l_pResult); + i_rData.Initialize(); + } + } + else + { + l_pResult = m_pBPool->Pull_Buffer(); + i_rData.Attach(l_pResult); + i_rData.Initialize(); + } + } + else + { + m_uHdrUsrSize = i_uSize + (tUINT32)sizeof(sH_User_Raw); + m_uHdrUsrChannel = i_uChannel_ID; + + sH_User_Raw l_sHeader = { INIT_USER_HEADER(m_uHdrUsrSize, m_uHdrUsrChannel) }; + + if (l_pResult) + { + i_rData.Attach(l_pResult); + if (sizeof(l_sHeader) >= i_rData.Get_Tail_Size()) + { + i_rData.Detach(); + m_pData_Queue_Out->Add_After(m_pData_Queue_Out->Get_Last(), l_pResult); + l_pResult = m_pBPool->Pull_Buffer(); + i_rData.Attach(l_pResult); + i_rData.Initialize(); + } + } + else + { + l_pResult = m_pBPool->Pull_Buffer(); + i_rData.Attach(l_pResult); + i_rData.Initialize(); + } + + m_pHdrUsrPacket = l_pResult; + m_pHdrUsrData = i_rData.Get_Tail(); + + memcpy(m_pHdrUsrData, &l_sHeader, sizeof(l_sHeader)); + i_rData.Append_Size((tUINT16)sizeof(l_sHeader)); + } + + LOCK_EXIT(m_hCS_Data_Out); + + return l_pResult; +}//Pull_Last_Data_Packet + + +//////////////////////////////////////////////////////////////////////////////// +//Push_Last_Data_Packet +tBOOL CClBaical::Push_Last_Data_Packet(CTPacket *i_pPacket) +{ + if (NULL == i_pPacket) + { + return FALSE; + } + + LOCK_ENTER(m_hCS_Data_Out); + + m_pData_Queue_Out->Add_After(m_pData_Queue_Out->Get_Last(), i_pPacket); + + LOCK_EXIT(m_hCS_Data_Out); + + return TRUE; +}//Push_Last_Data_Packet + +//////////////////////////////////////////////////////////////////////////////// +//Parse_Extensions +void CClBaical::Parse_Extensions(tUINT8 *i_pBuffer, size_t i_szBuffer) +{ + while (i_szBuffer > sizeof(sH_Ext)) + { + sH_Ext *l_pExt = (sH_Ext*)i_pBuffer; + + if (ETPE_SERVER_NETWORK_INFO == l_pExt->wType) + { + sH_Ext_Srv_Info *l_pInfo = (sH_Ext_Srv_Info*)(i_pBuffer + sizeof(sH_Ext)); + //for the time being ignore almost all fields, except buffer size on server side: + if (FALSE == m_bData_Wnd_Fixed) + { + //even if it will overflow we will check it in next IF + tUINT32 l_uiNewWndSize = (l_pInfo->dwSocket_Buffer / m_pBPool->Get_Buffer_Size()) - 1; + + //we will apply only server wnd value if it is less then local to fit in all limitations for both sides + if (l_uiNewWndSize < m_dwData_Wnd_Max_Count) + { + m_dwData_Wnd_Max_Count = l_uiNewWndSize; + } + } + } + else if (ETPE_USER_DATA == l_pExt->wType) + { + //skip here + } + else + { + JOURNAL_ERROR(m_pLog, TM("Unknown extension packet [%d:%d]"), (tUINT32)l_pExt->wType, (tUINT32)l_pExt->wSize); + } + + i_pBuffer += l_pExt->wSize; + i_szBuffer -= l_pExt->wSize; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//Parse_User_Data +void CClBaical::Parse_User_Data(tUINT8 *i_pBuffer, size_t i_szBuffer) +{ + tUINT32 l_dwChannelId = 0; + tUINT32 l_dwPacketSize = 0; + IP7C_Channel *l_pChannel = NULL; + tUINT8 *l_pStop = i_pBuffer + i_szBuffer; + + LOCK_ENTER(m_hCS_Reg); + + while (i_pBuffer < l_pStop) + { + l_dwChannelId = GET_USER_HEADER_CHANNEL_ID(((sH_User_Raw*)i_pBuffer)->dwBits); + l_dwPacketSize = GET_USER_HEADER_SIZE(((sH_User_Raw*)i_pBuffer)->dwBits); + + if (USER_PACKET_CHANNEL_ID_MAX_SIZE > l_dwChannelId) + { + l_pChannel = m_pChannels[l_dwChannelId]; + } + + if (l_pChannel) + { + l_pChannel->On_Receive(l_dwChannelId, + i_pBuffer + sizeof(sH_User_Data), + l_dwPacketSize - sizeof(sH_User_Data), + m_bBig_Endian + ); + } + else + { + JOURNAL_ERROR(m_pLog, + TM("Channel %d is not registered!"), + l_dwChannelId + ); + } + + i_pBuffer += l_dwPacketSize; + } + + LOCK_EXIT(m_hCS_Reg); +} + + +//////////////////////////////////////////////////////////////////////////////// +//Update_Channels_Status +void CClBaical::Update_Channels_Status(tBOOL i_bConnected, tUINT32 i_dwResets) +{ + sP7C_Status l_sStatus = {FALSE, 0}; + l_sStatus.bConnected = i_bConnected; + l_sStatus.dwResets = i_dwResets; + + LOCK_ENTER(m_hCS_Reg); + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus); + } + } + LOCK_EXIT(m_hCS_Reg); +}//Update_Channels_Status + + +//////////////////////////////////////////////////////////////////////////////// +//Comm_Routine +void CClBaical::Comm_Routine() +{ + tUINT32 l_dwExit_Signal_Time = 0; + tBOOL l_bExit_Signal = FALSE; + tBOOL l_bExit = FALSE; + tUINT32 l_dwSignal = MEVENT_TIME_OUT; + tUINT32 l_dwWait_TimeOut = COMMUNICATION_THREAD_IDLE_TIMEOUT; + CTPacket *l_pReceived_Packet = NULL; + CTPacket *l_pSent_Packet = NULL; + tUINT32 l_dwReceived = 0; + tBOOL l_bConnected_Cur = FALSE; + sockaddr_storage l_tAddress; + + memset(&l_tAddress, 0, sizeof(l_tAddress)); + + while (FALSE == l_bExit) + { + l_dwSignal = m_cComm_Event.Wait(l_dwWait_TimeOut); + + if (THREAD_EXIT_SIGNAL == l_dwSignal) + { + l_dwExit_Signal_Time = GetTickCount(); + l_bExit_Signal = TRUE; + } + + //have to close thread .... + if ( l_bExit_Signal ) + { + if (Is_Ready_To_Exit()) + { + Inc_Packet_ID(&m_dwLast_Packet_ID); + m_cPacket_Bye.Finalize(m_dwLast_Packet_ID, m_wClient_ID); + + if (UDP_SOCKET_OK != m_pSocket->Send((char*)m_cPacket_Bye.Get_Buffer(), + m_cPacket_Bye.Get_Size()) + ) + { + JOURNAL_ERROR(m_pLog, TM("<<< m_pSocket->Send Failed")); + } + + l_bExit = TRUE; + } + else if (CTicks::Difference(GetTickCount(), l_dwExit_Signal_Time) > m_dwExit_TimeOut) + { + JOURNAL_ERROR(m_pLog, + TM("Exit imeout is exceed, not of all packets were sent !")); + l_bExit = TRUE; + } + } + + if ( (MEVENT_TIME_OUT == l_dwSignal) + && (FALSE == l_bExit) + ) + { + //initiate timeout value, if we receive something or will be ready to send we will put 0 as value + l_dwWait_TimeOut = COMMUNICATION_THREAD_IDLE_TIMEOUT; + + if (NULL == l_pReceived_Packet) + { + l_pReceived_Packet = m_pBPool->Pull_Buffer(); + } + + if (l_pReceived_Packet) + { + l_dwReceived = 0; + if (UDP_SOCKET_OK == m_pSocket->Recv(&l_tAddress, + (char*)l_pReceived_Packet->Get_Buffer(), + l_pReceived_Packet->Get_Buffer_Size(), + &l_dwReceived, + m_bIs_Response_Waiting ? SOCKET_RECEIVE_RESPONSE_TIMEOUT : 0 + ) + ) + { + if ( (l_dwReceived) + && (FALSE == m_pSocket->Is_Server_Address(&l_tAddress)) + ) + { + l_dwReceived = 0; + JOURNAL_ERROR(m_pLog, + TM("<<<: Packet from wrong adress !")); + } + + if (l_dwReceived) + { + PACKET_PRINT(m_pLog, TM("[INP]"), l_pReceived_Packet); + + //l_pPacket will be freed inside function or stored ... + Process_Incoming_Packet(l_pReceived_Packet); + + //////////////////////////////////////////////////////// + // We pass packet to the stream, now packet it is head + // pain of the stream, we can forget about it + //////////////////////////////////////////////////////// + l_pReceived_Packet = NULL; + l_dwWait_TimeOut = 0; + } + } + } + + while ((l_pSent_Packet = Get_Delivered_Packet()) != NULL) + { + l_dwWait_TimeOut = 0; + PACKET_PRINT(m_pLog, TM("[OUT]"), l_pSent_Packet); + + if (UDP_SOCKET_OK != m_pSocket->Send((char*)l_pSent_Packet->Get_Buffer(), + l_pSent_Packet->Get_Size()) + ) + { + //nothing to do ... continue sending .... + //error message will be printed inside socket object + } + } + + l_bConnected_Cur = m_bConnected; + + if (COMMUNICATION_MAX_DELIVERY_FAILS <= m_dwDelivery_Fails) + { + l_bConnected_Cur = FALSE; + } + else + { + l_bConnected_Cur = TRUE; + } + + if (l_bConnected_Cur != m_bConnected) + { + if (FALSE == l_bConnected_Cur) + { + //clear connection event, it used to wait for connection + m_bConn_Event = TRUE; + m_cConn_Event.Clr(CONNECTION_SIGNAL); + + Set_Connected(FALSE); + Reset_Connetion();// << Update_Channels_Status(...) + JOURNAL_INFO(m_pLog, TM("------->Drop Connection<-------")); + } + else + { + Set_Connected(TRUE); + //after Set_Connected because they can update m_bConnected, + //m_dwConnection_Resets + Update_Channels_Status(m_bConnected, m_dwConnection_Resets); + JOURNAL_INFO(m_pLog, TM("<-------Establish Connection------->")); + } + } + } // if (WAIT_TIMEOUT == l_dwSignal) + }//while (FALSE == l_bExit) + + + if (l_pReceived_Packet) + { + m_pBPool->Push_Buffer(l_pReceived_Packet); + l_pReceived_Packet = NULL; + } +}//Comm_Routine + + +//////////////////////////////////////////////////////////////////////////////// +//Chnl_Routine +void CClBaical::Chnl_Routine() +{ + tBOOL l_bExit = FALSE; + tUINT32 l_dwSignal = 0; + pAList_Cell l_pElement = NULL; + CTPacket *l_pPacket = NULL; + + while (FALSE == l_bExit) + { + l_dwSignal = m_cChnl_Event.Wait(INFINITE); + + if (THREAD_EXIT_SIGNAL == l_dwSignal) + { + l_bExit = TRUE; + } + else if (THREAD_DATA_SIGNAL == l_dwSignal) + { + l_pPacket = NULL; + + LOCK_ENTER(m_hCS_Data_In); + l_pElement = m_pData_Queue_In->Get_First(); + if (l_pElement) + { + l_pPacket = m_pData_Queue_In->Get_Data(l_pElement); + m_pData_Queue_In->Del(l_pElement, FALSE); + } + LOCK_EXIT(m_hCS_Data_In); + + if (l_pPacket) + { + if (TPACKET_FLAG_EXTENSION & l_pPacket->Get_Flags()) //new server case v>4.3 + { + tUINT8 *l_pBuffer = l_pPacket->Get_Buffer() + ACKNOWLEDGMENT_SIZE; + size_t l_szBuffer = (size_t)l_pPacket->Get_Size() - ACKNOWLEDGMENT_SIZE; + + while (l_szBuffer > sizeof(sH_Ext)) + { + sH_Ext *l_pExt = (sH_Ext*)l_pBuffer; + + if (ETPE_SERVER_NETWORK_INFO == l_pExt->wType) + { + //skip, was processed by communication thread + } + else if (ETPE_USER_DATA == l_pExt->wType) + { + Parse_User_Data(l_pBuffer + sizeof(sH_Ext), l_pExt->wSize - sizeof(sH_Ext)); + } + else + { + JOURNAL_ERROR(m_pLog, TM("Unknown extension packet [%d:%d]"), (tUINT32)l_pExt->wType, (tUINT32)l_pExt->wSize); + } + + l_pBuffer += l_pExt->wSize; + l_szBuffer -= l_pExt->wSize; + } + + } + else //old server case v<=4.3 + { + Parse_User_Data(l_pPacket->Get_Buffer() + ACKNOWLEDGMENT_SIZE, + (size_t)l_pPacket->Get_Size() - ACKNOWLEDGMENT_SIZE); + } + + m_pBPool->Push_Buffer(l_pPacket); + l_pPacket = NULL; + } + else + { + JOURNAL_ERROR(m_pLog, + TM("Get event [Data In], but no buffers were found!") + ); + } + } //else if ( (WAIT_OBJECT_0 + 1) == l_dwSignal) + } +}//Chnl_Routine + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Info +tBOOL CClBaical::Get_Info(sP7C_Info *o_pInfo) +{ + if (NULL == o_pInfo) + { + return FALSE; + } + + LOCK_ENTER(m_hCS); + + //memcpy(&(o_pInfo->sServer), m_pSocket->Get_Address(), sizeof(sockaddr_storage)); + + m_pBPool->Get_Memory_Info((tUINT32*)&o_pInfo->dwMem_Used, + (tUINT32*)&o_pInfo->dwMem_Free, + (tUINT32*)&o_pInfo->dwMem_Alloc + ); + + o_pInfo->dwReject_Mem = m_lReject_Mem; + o_pInfo->dwReject_Con = m_lReject_Con; + o_pInfo->dwReject_Int = m_lReject_Int; + + LOCK_EXIT(m_hCS); + + return TRUE; +}//Get_Info + + +//////////////////////////////////////////////////////////////////////////////// +//Flush +tBOOL CClBaical::Close() +{ + tBOOL l_bStack_Trace = TRUE; + + //////////////////////////////////////////////////////////////////////////// + //notify channels about closing + sP7C_Status l_sStatus = {FALSE, 0}; + l_sStatus.bConnected = FALSE; + l_sStatus.dwResets = 0; + + if (m_bFlushChannels) + { + LOCK_ENTER(m_hCS_Reg); + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + m_pChannels[l_dwI]->On_Flush(l_dwI, &l_bStack_Trace); + m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus); + } + } + LOCK_EXIT(m_hCS_Reg); + } + + + m_cComm_Event.Set(THREAD_EXIT_SIGNAL); + m_cChnl_Event.Set(THREAD_EXIT_SIGNAL); + + if (m_bComm_Thread) + { + if (TRUE == CThShell::Close(m_hComm_Thread, 60000)) + { + m_hComm_Thread = 0;//NULL; + m_bComm_Thread = FALSE; + } + else + { + JOURNAL_CRITICAL(m_pLog, TM("Can't close communication thread !")); + } + } + + if (m_bChnl_Thread) + { + if (TRUE == CThShell::Close(m_hChnl_Thread, 60000)) + { + m_hChnl_Thread = 0;//NULL; + m_bChnl_Thread = FALSE; + } + else + { + JOURNAL_CRITICAL(m_pLog, TM("Can't close channels thread !")); + } + } + + //to prevent sending new data + LOCK_ENTER(m_hCS); + m_bConnected = FALSE; + LOCK_EXIT(m_hCS); + + return TRUE; +}//Flush + + +//////////////////////////////////////////////////////////////////////////////// +//Flush +void CClBaical::Flush() +{ + //nothing to do, component is designed in such a way to deliver new data as + //fast as possible, nothing to flush +} + + +//////////////////////////////////////////////////////////////////////////////// +//Connection_Wait +tBOOL CClBaical::Connection_Wait(tUINT32 i_dwMilliseconds) +{ + if (CONNECTION_SIGNAL == m_cConn_Event.Wait(i_dwMilliseconds)) + { + return TRUE; + } + + return FALSE; +}//Connection_Wait + + +//////////////////////////////////////////////////////////////////////////////// +//Sent +eClient_Status CClBaical::Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + CTPacket *l_pPacket = NULL; + tUINT32 l_dwTotal_Size = i_dwSize + (tUINT32)sizeof(sH_User_Raw); + tUINT32 l_dwPacket_Size = 0; + //Wanr: variables without default value! + tBOOL l_bExit; + tUINT32 l_dwChunk_Offs; + CTPData l_cData; + + if (ECLIENT_STATUS_OK != m_eStatus) + { + ATOMIC_INC(&m_lReject_Int); + return m_eStatus; + } + + if ( (NULL == i_pChunks) + || (0 >= i_dwCount) + || (USER_PACKET_MAX_SIZE <= l_dwTotal_Size) + || (USER_PACKET_CHANNEL_ID_MAX_SIZE <= i_dwChannel_ID) + ) + { + //InterlockedIncrement(&m_lReject_Int); + return ECLIENT_STATUS_WRONG_PARAMETERS; + } + + //N.B. We do not check i_dwSize and real size of all chunks in release mode!!! +#ifdef _DEBUG + //tUINT32 l_dwReal_Size = 0; + //for (tUINT32 l_dwI = 0; l_dwI < i_dwCount; l_dwI ++) + //{ + // if (i_pChunks[l_dwI].pData) + // { + // l_dwReal_Size += i_pChunks[l_dwI].dwSize; + // } + // else + // { + // break; + // } + //} + // + //if (l_dwReal_Size != i_dwSize) + //{ + // ATOMIC_INC(&m_lReject_Int); + // return ECLIENT_STATUS_WRONG_PARAMETERS; + //} +#endif + + LOCK_ENTER(m_hCS); + + if (FALSE == m_bConnected) + { + ATOMIC_INC(&m_lReject_Con); + l_eReturn = ECLIENT_STATUS_OFF; + goto l_lExit; + } + + l_dwPacket_Size = m_pBPool->Get_Buffer_Size() - CLIENT_DATA_HEADER_SIZE; + + //if size is more than available ... + //If we will use all buffers from Pool for data - we can cause DoS. + //no packets in Pool for incoming data from server, communication is broken + if ( (l_dwTotal_Size + (l_dwPacket_Size * 3) ) + > (l_dwPacket_Size * m_pBPool->Get_Free_Count()) + ) + { + ATOMIC_INC(&m_lReject_Mem); + l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS; + goto l_lExit; + } + + l_bExit = FALSE; + l_dwChunk_Offs = 0; + + //extract last packet form data queue, and update header if new packet belongs to the same channel! + l_pPacket = Reuse_Data_Packet(l_cData, i_dwChannel_ID, i_dwSize); + + while ( (FALSE == l_bExit) + && (l_pPacket) + ) + { + //if packet free size is larger or equal to chunk size + if ( l_cData.Get_Tail_Size() >= i_pChunks->dwSize ) + { + memcpy(l_cData.Get_Tail(), + ((tUINT8*)i_pChunks->pData) + l_dwChunk_Offs, + i_pChunks->dwSize + ); + + l_cData.Append_Size((tUINT16)i_pChunks->dwSize); + + //current chunk was moved, we reduce chunks amount + --i_dwCount; + + //if there is no more chunks - move packet to queue + if (0 >= i_dwCount) + { + Push_Last_Data_Packet(l_pPacket); + l_cData.Detach(); + l_pPacket = NULL; + l_bExit = TRUE; + } + else + { + //we are finish with that chunk + //i_pChunks->dwSize = 0; + l_dwChunk_Offs = 0; + + //go to next chunk + i_pChunks ++; + + //if packet is filled - put it to data queue + if (0 >= l_cData.Get_Tail_Size()) + { + Push_Last_Data_Packet(l_pPacket); + l_cData.Detach(); + + l_pPacket = m_pBPool->Pull_Buffer(); + if (l_pPacket) + { + l_cData.Attach(l_pPacket); + l_cData.Initialize(); + } + else + { + l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS; + l_bExit = TRUE; + ATOMIC_INC(&m_lReject_Mem); + } + } + } + } + else //if chunk data is greater than packet free space + { + memcpy(l_cData.Get_Tail(), + ((tUINT8*)i_pChunks->pData) + l_dwChunk_Offs, + l_cData.Get_Tail_Size() + ); + l_dwChunk_Offs += l_cData.Get_Tail_Size(); + i_pChunks->dwSize -= l_cData.Get_Tail_Size(); + + l_cData.Append_Size(l_cData.Get_Tail_Size()); + + Push_Last_Data_Packet(l_pPacket); + l_cData.Detach(); + + l_pPacket = m_pBPool->Pull_Buffer(); + if (l_pPacket) + { + l_cData.Attach(l_pPacket); + l_cData.Initialize(); + } + else + { + l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS; + l_bExit = TRUE; + ATOMIC_INC(&m_lReject_Mem); + } + } + } //while (FALSE == l_bExit) + + +l_lExit: + + LOCK_EXIT(m_hCS); + + return l_eReturn; + +}//Sent diff --git a/p7lib/Sources/ClBaical.h b/p7lib/Sources/ClBaical.h new file mode 100644 index 0000000..f3d1a9f --- /dev/null +++ b/p7lib/Sources/ClBaical.h @@ -0,0 +1,184 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to baical server / +// over UDP / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLBAICAL_H +#define CLBAICAL_H + + +class CClBaical: + public CClient +{ + tINT32 volatile m_lReject_Mem; + tINT32 volatile m_lReject_Con; + tINT32 volatile m_lReject_Int; + + tBOOL m_bIs_Winsock; + CUDP_Socket *m_pSocket; + tUINT16 m_wClient_ID; + CBuffers_Pool *m_pBPool; + + CBList *m_pData_Wnd; + pAList_Cell m_pData_Wnd_Cell; + tBOOL m_bData_Wnd_Fixed; + tUINT32 m_dwData_Wnd_Max_Count; + tUINT32 m_dwData_Wnd_Size; + tUINT32 m_dwData_Wnd_TimeStamp; + tUINT32 m_dwData_Wnd_First_ID; + tUINT32 m_dwData_Wnd_Last_ID; + tBOOL m_bData_Resending; + + tUINT32 m_dwDelivery_Fails; + tBOOL m_bIs_Response_Waiting; + + CBList *m_pData_Queue_Out; + //need to synchronize updating m_pData_Queue by user and requests from internal threads + tLOCK m_hCS_Data_Out; + + CBList *m_pData_Queue_In; + tLOCK m_hCS_Data_In; + + tUINT32 m_dwLast_Packet_ID; + tUINT32 m_dwServiceTimeStamp; + + tUINT32 m_dwExit_TimeOut; + + //permanent packets, they do not consume a lot of memory and more + //practical have them always instead of taking them from pool + CTPacket *m_pPacket_Control; + CTPClient_Hello m_cPacket_Hello; + CTPData_Window m_cPacket_Data_Report; + CTPClient_Ping m_cPacket_Alive; + CTPClient_Bye m_cPacket_Bye; + tBOOL m_bBig_Endian; + + CMEvent m_cConn_Event; + tBOOL m_bConn_Event; + + CMEvent m_cComm_Event; + tBOOL m_bComm_Thread; + CThShell::tTHREAD m_hComm_Thread; + + CMEvent m_cChnl_Event; + tBOOL m_bChnl_Thread; + CThShell::tTHREAD m_hChnl_Thread; + + tBOOL m_bLocalHost; + + tBOOL m_bExtension; + + void *m_pHdrUsrData; + CTPacket *m_pHdrUsrPacket; + tUINT32 m_uHdrUsrSize; + tUINT32 m_uHdrUsrChannel; + +public: + CClBaical(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + virtual ~CClBaical(); + +private: + eClient_Status Init_Base(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + eClient_Status Init_Log(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + eClient_Status Init_Sockets(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + eClient_Status Init_Pool(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + eClient_Status Init_Members(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + //eClient_Status Init_Threads(tXCHAR **i_pArgs, + // tINT32 i_iCount + // ); + + void Inc_Packet_ID(tUINT32 * o_pPacketID); + + tBOOL Process_Incoming_Packet(CTPacket *i_pPacket); + CTPacket *Get_Delivered_Packet(); + tBOOL Is_Ready_To_Exit(); + + void Set_Connected(tBOOL i_bConnected); + + void Reset_Connetion(); + CTPacket *Create_Data_Wnd_Report(); + inline CTPacket *Pull_Firt_Data_Packet(); + inline CTPacket *Reuse_Data_Packet(CTPData &i_rData, tUINT32 i_uChannel, tUINT32 i_uSize); + inline tBOOL Push_Last_Data_Packet(CTPacket *i_pPacket); + + inline void Parse_Extensions(tUINT8 *i_pBuffer, size_t i_szBuffer); + + inline void Parse_User_Data(tUINT8 *i_pBuffer, size_t i_szBuffer); + + inline void Update_Channels_Status(tBOOL i_bConnected, tUINT32 i_dwResets); + + void Comm_Routine(); + void Chnl_Routine(); + +public: + tBOOL Connection_Wait(tUINT32 i_dwMilliseconds); + + eClient_Status Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ); + + tBOOL Get_Info(sP7C_Info *o_pInfo); + tBOOL Close(); + + virtual void Flush(); + +private: + static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_Comm_Routine(void *i_pContext) + { + CClBaical *l_pRoutine = static_cast(i_pContext); + if (l_pRoutine) + { + l_pRoutine->Comm_Routine(); + } + + CThShell::Cleanup(); + return THSHELL_RET_OK; + } + + static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_Chnl_Routine(void *i_pContext) + { + CClBaical *l_pRoutine = static_cast(i_pContext); + if (l_pRoutine) + { + l_pRoutine->Chnl_Routine(); + } + + CThShell::Cleanup(); + return THSHELL_RET_OK; + } +}; + + +#endif //CLBAICAL_H diff --git a/p7lib/Sources/ClFile.cpp b/p7lib/Sources/ClFile.cpp new file mode 100644 index 0000000..10c4e3b --- /dev/null +++ b/p7lib/Sources/ClFile.cpp @@ -0,0 +1,1351 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to file / +//////////////////////////////////////////////////////////////////////////////// + +#include "CommonClient.h" +#include "ClFile.h" + +#define THREAD_IDLE_TIMEOUT (10) +#define THREAD_WRITE_TIMEOUT (15000) + + +enum eThreadsEvents +{ + eThreadEventExit = MEVENT_SIGNAL_0, + eThreadEventHasData, + eThreadEventDataFlush, + eThreadEventsCount = 3 +}; + +#define MIN_BUFFER_SIZE (16384) +#define MAX_BUFFER_SIZE (131072) +#define MIN_BUFFERS_COUNT (3) + +#define DEF_FILES_COUNT (0) +#define MIN_FILES_COUNT (1) +#define MAX_FILES_COUNT (4096) + +#define DEF_POOL_SIZE (MAX_BUFFER_SIZE * 16) +#define MIN_POOL_SIZE (MIN_BUFFER_SIZE * MIN_BUFFERS_COUNT) + + +#define P7_EXT TM("p7d") + +#define TAIL_SIZE(iBuffer) (m_dwBuffer_Size - (tUINT32)iBuffer->szUsed) + +//////////////////////////////////////////////////////////////////////////////// +//CClFile() +CClFile::CClFile(tXCHAR **i_pArgs, tINT32 i_iCount) + : CClient(IP7_Client::eFileBin, i_pArgs, i_iCount) + , m_lReject_Mem(0) + , m_lReject_Con(0) + , m_lReject_Int(0) + , m_bThread(FALSE) + , m_hThread(0) //NULL + , m_pBuffer_Current(0) + , m_dwBuffer_Size(0) + , m_dwBuffers_Count(0) + , m_eRolling(EROLLING_NONE) + , m_qwRolling_Value(0) + , m_dwFile_Tick(0) + , m_qwFile_Size(0) + , m_dwFiles_Max_Count(DEF_FILES_COUNT) + , m_qwFiles_Max_Size(0u) + , m_dwIndex(0) +{ + memset(&m_cHeader, 0, sizeof(m_cHeader)); + + //1. base init + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Base(i_pArgs, i_iCount); + } + + //2. Initialize Pool + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Pool(i_pArgs, i_iCount); + } + + //3. Initialize file + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_File(i_pArgs, i_iCount); + } + + //4. Initialize variables + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Thread(i_pArgs, i_iCount); + } + + //5. Initialize crash handler + if (ECLIENT_STATUS_OK == m_eStatus) + { + Init_Crash_Handler(i_pArgs, i_iCount); + } +}//CClFile() + + +//////////////////////////////////////////////////////////////////////////////// +//~CClFile() +CClFile::~CClFile() +{ + Uninit_Crash_Handler(); + + Close(); + + if (m_pBuffer_Current) + { + delete m_pBuffer_Current; + m_pBuffer_Current = NULL; + } + + m_cBuffer_Empty.Clear(TRUE); + m_cBuffer_Ready.Clear(TRUE); + + m_cFiles.Clear(TRUE); + m_cSecondsList.Clear(TRUE); + + CClient::Unshare(); +}//~CClFile() + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Base +eClient_Status CClFile::Init_Base(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tUINT32 l_dwHTime = 0; + tUINT32 l_dwLTime = 0; + tXCHAR *l_pArg_Value = NULL; + tWCHAR l_pProc_Name[TPACKET_PROCESS_NAME_MAX_LEN * 2]; + + //////////////////////////////////////////////////////////////////////////// + //initialize header + memset(l_pProc_Name, 0, sizeof(tWCHAR) * LENGTH(l_pProc_Name)); + memset(&m_cHeader, 0, sizeof(m_cHeader)); + + CProc::Get_Process_Time(&l_dwHTime, &l_dwLTime); + + m_cHeader.qwMarker = P7_DAMP_FILE_MARKER_V1; + m_cHeader.dwProcess_ID = CProc::Get_Process_ID(); + m_cHeader.dwProcess_Start_Time_Hi = l_dwHTime; + m_cHeader.dwProcess_Start_Time_Lo = l_dwLTime; + + + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_NAME); + if (!l_pArg_Value) + { + CProc::Get_Process_Name(m_cHeader.pProcess_Name, P7_DAMP_FILE_PROCESS_LENGTH); + } + else + { + #ifdef UTF8_ENCODING + Convert_UTF8_To_UTF16((const char*)l_pArg_Value, + m_cHeader.pProcess_Name, + P7_DAMP_FILE_PROCESS_LENGTH + ); + #else + PStrCpy((tXCHAR*)m_cHeader.pProcess_Name, + P7_DAMP_FILE_PROCESS_LENGTH, + l_pArg_Value + ); + #endif + } + + CSys::Get_Host_Name(m_cHeader.pHost_Name, P7_DAMP_FILE_HOST_LENGTH); + + return l_eReturn; +}//Init_Base + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Pool +eClient_Status CClFile::Init_Pool(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tXCHAR *l_pArg_Value = NULL; + tUINT32 l_dwPool_Size = DEF_POOL_SIZE; + tUINT32 l_dwBuffer_Size = MAX_BUFFER_SIZE * 2; + tUINT32 l_dwBuffers_Count = 0; + pAList_Cell l_pEl = NULL; + + //////////////////////////////////////////////////////////////////////////// + //getting pool size + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_POOL_SIZE); + if (l_pArg_Value) + { + l_dwPool_Size = 1024 * (tUINT32)PStrToInt(l_pArg_Value); + + if (MIN_POOL_SIZE > l_dwPool_Size) + { + l_dwPool_Size = MIN_POOL_SIZE; + } + } + + //////////////////////////////////////////////////////////////////////////// + //calculate buffer size and buffers count + //Starting from largest buffer size trying to calculate how much buffers we + //can allocate, is amount is smaller than minimum - device buffer size by 2 + //and repeat procedure + while (l_dwBuffers_Count < MIN_BUFFERS_COUNT) + { + l_dwBuffer_Size /= 2; + l_dwBuffers_Count = l_dwPool_Size / l_dwBuffer_Size; + } + + if ( (MIN_BUFFER_SIZE > l_dwBuffer_Size) + || (MIN_BUFFERS_COUNT > l_dwBuffers_Count) + ) + { + JOURNAL_ERROR(m_pLog, + TM("Pool: Memory calculation error, buffer size = %d, buffers count = %d"), + l_dwBuffer_Size, + l_dwBuffers_Count + ); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + P7_Set_Last_Error(eP7_Error_UserSettings); + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //allocate buffers + m_dwBuffer_Size = l_dwBuffer_Size; + m_dwBuffers_Count = l_dwBuffers_Count; + + for (tUINT32 l_dwI = 0; l_dwI < m_dwBuffers_Count; l_dwI++) + { + sBuffer *l_pBuffer = new sBuffer(m_dwBuffer_Size); + if (l_pBuffer) + { + m_cBuffer_Empty.Add_After(NULL, l_pBuffer); + } + else + { + JOURNAL_ERROR(m_pLog, TM("Pool: Memory calculation failed")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + goto l_lblExit; + } + } + + + //////////////////////////////////////////////////////////////////////////// + //copy header to buffer + l_pEl = m_cBuffer_Empty.Get_First(); + m_pBuffer_Current = m_cBuffer_Empty.Get_Data(l_pEl); + m_cBuffer_Empty.Del(l_pEl, FALSE); + + if (m_dwBuffer_Size > sizeof(m_cHeader)) + { + memcpy(m_pBuffer_Current->pBuffer, + &m_cHeader, + sizeof(m_cHeader) + ); + + m_pBuffer_Current->szUsed += sizeof(m_cHeader); + } + else + { + JOURNAL_ERROR(m_pLog, TM("Pool: Not enough memory")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + P7_Set_Last_Error(eP7_Error_UserSettings); + goto l_lblExit; + } + + +l_lblExit: + return l_eReturn; +}//Init_Pool + + +//////////////////////////////////////////////////////////////////////////////// +//Init_File +eClient_Status CClFile::Init_File(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tXCHAR *l_pArgV = NULL; + pAList_Cell l_pStart = NULL; + tUINT32 l_dwDirLen = 0; + + m_pDir.Realloc(4096); + + //////////////////////////////////////////////////////////////////////////// + //get maximum count of the log files + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_FILES_COUNT_MAX + ); + if (l_pArgV) + { + m_dwFiles_Max_Count = (tUINT32)PStrToInt(l_pArgV); + + if ( (MIN_FILES_COUNT > m_dwFiles_Max_Count) + || (MAX_FILES_COUNT < m_dwFiles_Max_Count) + ) + { + m_dwFiles_Max_Count = DEF_FILES_COUNT; + } + } + + + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_FILES_SIZE_MAX + ); + if (l_pArgV) + { + m_qwFiles_Max_Size = (tUINT64)PStrToInt(l_pArgV) * 1048576ull; + } + + //////////////////////////////////////////////////////////////////////////// + //get path to storage + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_DIR + ); + if (l_pArgV) + { + m_pDir.Set(l_pArgV); + } + else + { + CProc::Get_Process_Path(m_pDir.Get(), m_pDir.Max_Length()); + m_pDir.Append(1, TM("/P7logs/")); + } + + if (FALSE == CFSYS::Directory_Exists(m_pDir.Get())) + { + if (FALSE == CFSYS::Directory_Create(m_pDir.Get())) + { + JOURNAL_ERROR(m_pLog, TM("Can't create directory: %s"), l_pArgV); + l_eReturn = ECLIENT_STATUS_NOT_ALLOWED; + P7_Set_Last_Error(eP7_Error_FolderCreation); + goto l_lblExit; + } + } + + //////////////////////////////////////////////////////////////////////////// + //enumerate files & sorting .... + if ( (DEF_FILES_COUNT != m_dwFiles_Max_Count) + || (m_qwFiles_Max_Size) + ) + { + CFSYS::Enumerate_Files(&m_cFiles, &m_pDir, TM("*.") P7_EXT, 0); + + l_pStart = NULL; + l_dwDirLen = m_pDir.Length(); + + while ((l_pStart = m_cFiles.Get_Next(l_pStart))) + { + pAList_Cell l_pMin = l_pStart; + pAList_Cell l_pIter = l_pStart; + + while ((l_pIter = m_cFiles.Get_Next(l_pIter))) + { + CWString *l_pPathM = m_cFiles.Get_Data(l_pMin); + CWString *l_pPathI = m_cFiles.Get_Data(l_pIter); + tXCHAR *l_pNameM = l_pPathM->Get() + l_dwDirLen; + tXCHAR *l_pNameI = l_pPathI->Get() + l_dwDirLen; + + if (0 < PStrICmp(l_pNameM, l_pNameI)) + { + l_pMin = l_pIter; + } + } + + if (l_pMin != l_pStart) + { + m_cFiles.Extract(l_pMin); + m_cFiles.Put_After(m_cFiles.Get_Prev(l_pStart), l_pMin); + l_pStart = l_pMin; + } + } //while (l_pStart = m_cFiles.Get_Next(l_pStart)) + } + + //////////////////////////////////////////////////////////////////////////// + //create file + l_eReturn = Create_File(); + if (ECLIENT_STATUS_OK != l_eReturn) + { + P7_Set_Last_Error(eP7_Error_FileCreation); + JOURNAL_ERROR(m_pLog, TM("File creation failed {%s}"), l_pArgV); + goto l_lblExit; + } + + + //////////////////////////////////////////////////////////////////////////// + //get rolling type + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_FILE_ROLLING + ); + if (l_pArgV) + { + CWString l_cRolling(l_pArgV); + tUINT32 l_dwLen = l_cRolling.Length(); + tBOOL l_bError = FALSE; + + if (3 <= l_dwLen) + { + tXCHAR *l_pSuffix = l_cRolling.Get() + l_dwLen - 2; + if (0 == PStrICmp(l_pSuffix, TM("hr"))) + { + m_eRolling = EROLLING_HOURS; + } + else if (0 == PStrICmp(l_pSuffix, TM("mb"))) + { + m_eRolling = EROLLING_MEGABYTES; + } + else if (0 == PStrICmp(l_pSuffix, TM("tm"))) + { + m_eRolling = EROLLING_TIME; + } + else + { + l_bError = TRUE; + } + + //cut off suffix + l_cRolling.Trim(l_dwLen - 2); + } + else + { + l_bError = TRUE; + } + + if (FALSE == l_bError) + { + if (m_eRolling != EROLLING_TIME) + { + m_qwRolling_Value = PStrToInt(l_cRolling.Get()); + + if (0 >= m_qwRolling_Value) + { + m_eRolling = EROLLING_NONE; + l_bError = TRUE; + } + } + else + { + if (!Parse_Rolling_Time(l_cRolling.Get())) + { + m_eRolling = EROLLING_NONE; + l_bError = TRUE; + } + } + } + + if (l_bError) + { + JOURNAL_ERROR(m_pLog, TM("Rolling value is not correct = %s"), l_cRolling.Get()); + } + + if (EROLLING_MEGABYTES == m_eRolling) + { + m_qwRolling_Value *= 0x100000ULL; //megabytes + } + else if (EROLLING_HOURS == m_eRolling) + { + if (m_qwRolling_Value > 1000) + { + JOURNAL_ERROR(m_pLog, TM("Rolling value is more than 1000 hours, cutting")); + m_qwRolling_Value = 1000; + } + + m_qwRolling_Value *= 3600000ULL; //milliseconds in one hour + } + }//if (l_pArgV) + +l_lblExit: + return l_eReturn; +}//Init_File + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Thread +eClient_Status CClFile::Init_Thread(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + + UNUSED_ARG(i_pArgs); + UNUSED_ARG(i_iCount); + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == m_cEvent.Init(eThreadEventsCount, EMEVENT_SINGLE_AUTO, EMEVENT_MULTI, EMEVENT_SINGLE_AUTO)) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == CThShell::Create(&Static_Routine, + this, + &m_hThread, + TM("P7:Comm") + ) + ) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Communication thread wasn't created !")); + } + else + { + m_bThread = TRUE; + } + } + + return l_eReturn; +}//Init_Thread + + +//////////////////////////////////////////////////////////////////////////////// +// Create_File +eClient_Status CClFile::Create_File() +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tUINT32 l_dwYear = 0; + tUINT32 l_dwMonth = 0; + tUINT32 l_dwDay = 0; + tUINT32 l_dwHr = 0; + tUINT32 l_dwMin = 0; + tUINT32 l_dwSec = 0; + tUINT32 l_dwmSec = 0; + CWString l_cFilePath; + tXCHAR l_pFile_Name[64]; + + m_cFile.Close(TRUE); + + CSys::Get_DateTime(l_dwYear, + l_dwMonth, + l_dwDay, + l_dwHr, + l_dwMin, + l_dwSec, + l_dwmSec + ); + l_dwmSec = 0; + do + { + PSPrint(l_pFile_Name, + LENGTH(l_pFile_Name), + TM("/%04d%02d%02d-%02d%02d%02d.%03d.") P7_EXT, + l_dwYear, + l_dwMonth, + l_dwDay, + l_dwHr, + l_dwMin, + l_dwSec, + m_dwIndex + ); + + l_cFilePath.Set(m_pDir.Get()); + l_cFilePath.Append(1, l_pFile_Name); + + m_dwIndex ++; + } while (TRUE == CFSYS::File_Exists(l_cFilePath.Get())); + + if (FALSE == m_cFile.Open(l_cFilePath.Get(), + IFile::ECREATE | IFile::EACCESS_WRITE | IFile::ESHARE_READ + ) + ) + { + JOURNAL_ERROR(m_pLog, TM("Can't create file: %s"), l_cFilePath.Get()); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + else + { + m_cFiles.Add_After(m_cFiles.Get_Last(), new CWString(l_cFilePath.Get())); + + if (DEF_FILES_COUNT != m_dwFiles_Max_Count) + { + while (m_dwFiles_Max_Count < m_cFiles.Count()) + { + pAList_Cell l_pEl = m_cFiles.Get_First(); + CWString *l_pPath = m_cFiles.Get_Data(l_pEl); + if (l_pPath) + { + if (!CFSYS::Delete_File(l_pPath->Get())) + { + JOURNAL_ERROR(m_pLog, TM("Can't delete file: %s"), l_pPath->Get()); + } + } + + m_cFiles.Del(l_pEl, TRUE); + } + } + + if (0 != m_qwFiles_Max_Size) + { + pAList_Cell l_pEl = NULL; + tUINT64 l_qwTotalSize = 0; + tUINT64 l_qwFileSize = 0; + + while ((l_pEl = m_cFiles.Get_Next(l_pEl))) + { + CWString *l_pPath = m_cFiles.Get_Data(l_pEl); + if (l_pPath) + { + l_qwTotalSize += CFSYS::Get_File_Size(l_pPath->Get()); + } + } + + while (l_qwTotalSize > ((tUINT64)m_qwFiles_Max_Size)) + { + pAList_Cell l_pEl = m_cFiles.Get_First(); + CWString *l_pPath = m_cFiles.Get_Data(l_pEl); + if (l_pPath) + { + l_qwFileSize = CFSYS::Get_File_Size(l_pPath->Get()); + + if (l_qwFileSize < l_qwTotalSize) + { + l_qwTotalSize -= l_qwFileSize; + } + else + { + l_qwTotalSize = 0ull; + } + + if (!CFSYS::Delete_File(l_pPath->Get())) + { + JOURNAL_ERROR(m_pLog, TM("Can't delete file: %s"), l_pPath->Get()); + } + } + + m_cFiles.Del(l_pEl, TRUE); + } + } + } + + m_dwFile_Tick = GetTickCount(); + + return l_eReturn; +}// Create_File + + +//////////////////////////////////////////////////////////////////////////////// +//Parse_Rolling_Time +tBOOL CClFile::Parse_Rolling_Time(const tXCHAR *i_pTime) +{ + const tXCHAR *l_pIter = i_pTime; + const tXCHAR *l_pBegin = i_pTime; + tBOOL l_bReturn = TRUE; + + while (*l_pIter) + { + tUINT32 l_uiSeconds = 0; + tUINT32 l_uiValue = 0; + + l_pBegin = l_pIter; //scan hours + while ( (*l_pIter >= TM('0')) + && (*l_pIter <= TM('9')) + ) + { + l_uiValue = l_uiValue * 10 + (*l_pIter - TM('0')); + l_pIter ++; + } + + if (l_pBegin == l_pIter) //no digits + { + l_bReturn = FALSE; + break; + } + + l_uiSeconds = l_uiValue * 3600; + + if (*l_pIter != TM(':')) //error + { + l_bReturn = FALSE; + break; + } + + l_pIter++; + + l_pBegin = l_pIter; //scan minutes + l_uiValue = 0; + while ( (*l_pIter >= TM('0')) + && (*l_pIter <= TM('9')) + ) + { + l_uiValue = l_uiValue * 10 + (*l_pIter - TM('0')); + l_pIter ++; + } + + if (l_pBegin == l_pIter) //no digits + { + l_bReturn = FALSE; + break; + } + + l_uiSeconds += l_uiValue * 60; + + m_cSecondsList.Add_After(m_cSecondsList.Get_Last(), l_uiSeconds); + + if (*l_pIter == TM(',')) + { + l_pIter++; + } + } + + if (!m_cSecondsList.Count()) + { + l_bReturn = FALSE; + } + + return l_bReturn; +}//Parse_Rolling_Time + + +//////////////////////////////////////////////////////////////////////////////// +//Sent +eClient_Status CClFile::Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tUINT32 l_dwTotal_Size = i_dwSize + (tUINT32)sizeof(sH_User_Raw); + sH_User_Raw l_sHeader = {INIT_USER_HEADER(l_dwTotal_Size, i_dwChannel_ID)}; + sP7C_Data_Chunk l_sHeader_Chunk = {&l_sHeader, (tUINT32)sizeof(l_sHeader)}; + //Wanr: variables without default value! + tBOOL l_bExit; + sP7C_Data_Chunk *l_pChunk; + tUINT32 l_dwChunk_Offs; + pAList_Cell l_pEl; + tUINT32 l_dwFree_Size; + + if (ECLIENT_STATUS_OK != m_eStatus) + { + ATOMIC_INC(&m_lReject_Int); + return m_eStatus; + } + + if ( (NULL == i_pChunks) + || (0 >= i_dwCount) + || (USER_PACKET_MAX_SIZE <= l_dwTotal_Size) + || (USER_PACKET_CHANNEL_ID_MAX_SIZE <= i_dwChannel_ID) + ) + { + ATOMIC_INC(&m_lReject_Int); + return ECLIENT_STATUS_WRONG_PARAMETERS; + } + + //N.B. We do not check i_dwSize and real size of all chunks in release mode!!! +#ifdef _DEBUG + tUINT32 l_dwReal_Size = 0; + for (tUINT32 l_dwI = 0; l_dwI < i_dwCount; l_dwI ++) + { + if (i_pChunks[l_dwI].pData) + { + l_dwReal_Size += i_pChunks[l_dwI].dwSize; + } + else + { + break; + } + } + + if (l_dwReal_Size != i_dwSize) + { + ATOMIC_INC(&m_lReject_Int); + return ECLIENT_STATUS_WRONG_PARAMETERS; + } +#endif + + + LOCK_ENTER(m_hCS); + + if (FALSE == m_bConnected) + { + l_eReturn = ECLIENT_STATUS_OFF; + ATOMIC_INC(&m_lReject_Con); + goto l_lExit; + } + + l_dwFree_Size = (m_cBuffer_Empty.Count() * m_dwBuffer_Size) + + ((m_pBuffer_Current) ? (m_dwBuffer_Size - (tUINT32)m_pBuffer_Current->szUsed) : 0); + + //if size is more than available ... + if (l_dwFree_Size < l_dwTotal_Size) + { + l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS; + ATOMIC_INC(&m_lReject_Mem); + goto l_lExit; + } + + + //because we add header as chunk + i_dwCount ++; + + l_bExit = FALSE; + l_pChunk = &l_sHeader_Chunk; //&i_pChunks[0]; + l_dwChunk_Offs = 0; + + while (FALSE == l_bExit) + { + //if packet is null we need to extract another one + if (NULL == m_pBuffer_Current) + { + l_pEl = m_cBuffer_Empty.Get_First(); + m_pBuffer_Current = m_cBuffer_Empty.Get_Data(l_pEl); + m_cBuffer_Empty.Del(l_pEl, FALSE); + } + + while ( (m_pBuffer_Current) + && (i_dwCount) + ) + { + //if packet free size is larger or equal to chunk size + if ( TAIL_SIZE(m_pBuffer_Current) >= l_pChunk->dwSize ) + { + memcpy(m_pBuffer_Current->pBuffer + m_pBuffer_Current->szUsed, + ((tUINT8*)l_pChunk->pData) + l_dwChunk_Offs, + l_pChunk->dwSize + ); + + m_pBuffer_Current->szUsed += l_pChunk->dwSize; + + //current chunk was moved, we reduce chunks amount + --i_dwCount; + + if (0 >= i_dwCount) + { + l_bExit = TRUE; + } + else + { + //we are finish with that chunk + //l_pChunk->dwSize = 0; + l_dwChunk_Offs = 0; + + if (l_pChunk == &l_sHeader_Chunk) + { + l_pChunk = &i_pChunks[0]; + } + else + { + //go to next chunk + l_pChunk ++; + } + + //if packet is filled - put it to data queue + if (0 >= TAIL_SIZE(m_pBuffer_Current)) + { + m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), + m_pBuffer_Current + ); + m_pBuffer_Current = NULL; + m_cEvent.Set(eThreadEventHasData); + } + } + } + else //if chunk data is greater than packet free space + { + memcpy(m_pBuffer_Current->pBuffer + m_pBuffer_Current->szUsed, + ((tUINT8*)l_pChunk->pData) + l_dwChunk_Offs, + TAIL_SIZE(m_pBuffer_Current) + ); + l_dwChunk_Offs += TAIL_SIZE(m_pBuffer_Current); + l_pChunk->dwSize -= TAIL_SIZE(m_pBuffer_Current); + + m_pBuffer_Current->szUsed += TAIL_SIZE(m_pBuffer_Current); + + m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), + m_pBuffer_Current + ); + m_pBuffer_Current = NULL; + m_cEvent.Set(eThreadEventHasData); + } + } //while ( (m_pBuffer_Current) && (i_dwCount) ) + } //while (FALSE == l_bExit) + +l_lExit: + + LOCK_EXIT(m_hCS); + + return l_eReturn; +}//Sent + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Info +tBOOL CClFile::Get_Info(sP7C_Info *o_pInfo) +{ + if (NULL == o_pInfo) + { + return FALSE; + } + + LOCK_ENTER(m_hCS); + + o_pInfo->dwMem_Alloc = m_dwBuffer_Size * m_dwBuffers_Count; + o_pInfo->dwMem_Free = m_cBuffer_Empty.Count() * m_dwBuffer_Size; + o_pInfo->dwMem_Used = m_cBuffer_Ready.Count() * m_dwBuffer_Size; + + o_pInfo->dwReject_Mem = m_lReject_Mem; + o_pInfo->dwReject_Con = m_lReject_Con; + o_pInfo->dwReject_Int = m_lReject_Int; + LOCK_EXIT(m_hCS); + + return TRUE; +}//Get_Info + + +//////////////////////////////////////////////////////////////////////////////// +//Flush +tBOOL CClFile::Close() +{ + tBOOL l_bStack_Trace = TRUE; + + //////////////////////////////////////////////////////////////////////////// + //notify channels about closing + sP7C_Status l_sStatus = {FALSE, 0}; + l_sStatus.bConnected = FALSE; + l_sStatus.dwResets = 0; + + if (m_bFlushChannels) + { + LOCK_ENTER(m_hCS_Reg); + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + m_pChannels[l_dwI]->On_Flush(l_dwI, &l_bStack_Trace); + m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus); + } + } + LOCK_EXIT(m_hCS_Reg); + } + + m_cEvent.Set(eThreadEventExit); + + if (m_bThread) + { + if (TRUE == CThShell::Close(m_hThread, 60000)) + { + m_hThread = 0;//NULL; + m_bThread = FALSE; + } + else + { + JOURNAL_CRITICAL(m_pLog, TM("Can't close file thread !")); + } + } + + //////////////////////////////////////////////////////////////////////////// + //Lock + LOCK_ENTER(m_hCS); + + if (m_bConnected) + { + pAList_Cell l_pEl = NULL; + while ((l_pEl = m_cBuffer_Ready.Get_Next(l_pEl))) + { + sBuffer *l_pBuffer = m_cBuffer_Ready.Get_Data(l_pEl); + if (l_pBuffer) + { + //m_qwFile_Size += l_pBuffer->szUsed; //for debug + + if (l_pBuffer->szUsed != m_cFile.Write(l_pBuffer->pBuffer, + l_pBuffer->szUsed, + FALSE + ) + ) + { + JOURNAL_CRITICAL(m_pLog, TM("Can't write to file !")); + m_bConnected = FALSE; + break; + } + } + } + } + + if (m_pBuffer_Current) + { + if ( (m_bConnected) + && (m_pBuffer_Current->szUsed) + ) + { + //m_qwFile_Size += m_pBuffer_Current->szUsed; //for debug + + if (m_pBuffer_Current->szUsed != m_cFile.Write(m_pBuffer_Current->pBuffer, + m_pBuffer_Current->szUsed, + FALSE + ) + ) + { + JOURNAL_CRITICAL(m_pLog, TM("Can't write to file !")); + m_bConnected = FALSE; + } + } + } + + m_bConnected = FALSE; + + LOCK_EXIT(m_hCS); + //unlock + //////////////////////////////////////////////////////////////////////////// + + m_cFile.Close(TRUE); + + return TRUE; +}//Flush + + +//////////////////////////////////////////////////////////////////////////////// +//Flush +void CClFile::Flush() +{ + m_cEvent.Set(eThreadEventDataFlush); +} + + +//////////////////////////////////////////////////////////////////////////////// +//Roll +void CClFile::Roll() +{ + CBList l_cBuffers; + sBuffer *l_pBuffer = NULL; + pAList_Cell l_pEl = NULL; + tBOOL l_bError = FALSE; + tBOOL l_bHeader = FALSE; + tBOOL l_bUpdate = FALSE; + + if (FALSE == m_bConnected) + { + return; + } + + //////////////////////////////////////////////////////////////////////////// + // + LOCK_ENTER(m_hCS); + //move ready buffers to temporary list + while ((l_pEl = m_cBuffer_Ready.Get_First())) + { + l_cBuffers.Add_After(l_cBuffers.Get_Last(), + m_cBuffer_Ready.Get_Data(l_pEl) + ); + + m_cBuffer_Ready.Del(l_pEl, FALSE); + } + + if (m_pBuffer_Current) + { + l_cBuffers.Add_After(l_cBuffers.Get_Last(), m_pBuffer_Current); + m_pBuffer_Current = NULL; + } + + //////////////////////////////////////////////////////////////////////////// + //update reset count and file size + m_dwConnection_Resets ++; + m_qwFile_Size = 0; + + //////////////////////////////////////////////////////////////////////////// + //copy header to current buffer + l_pEl = m_cBuffer_Empty.Get_First(); + if (l_pEl) + { + m_pBuffer_Current = m_cBuffer_Empty.Get_Data(l_pEl); + m_cBuffer_Empty.Del(l_pEl, FALSE); + + memcpy(m_pBuffer_Current->pBuffer, + &m_cHeader, + sizeof(m_cHeader) + ); + + m_pBuffer_Current->szUsed += sizeof(m_cHeader); + l_bHeader = TRUE; + } + + LOCK_EXIT(m_hCS); + // + //////////////////////////////////////////////////////////////////////////// + + //m_dwConnection_Resets will be updated ! + Update_Channels_Status(m_bConnected, m_dwConnection_Resets); + + + //////////////////////////////////////////////////////////////////////////// + //writing data + l_pEl = NULL; + while ((l_pEl = l_cBuffers.Get_Next(l_pEl))) + { + l_pBuffer = l_cBuffers.Get_Data(l_pEl); + + if (l_pBuffer->szUsed > m_cFile.Write(l_pBuffer->pBuffer, l_pBuffer->szUsed, FALSE)) + { + JOURNAL_CRITICAL(m_pLog, TM("Not possible to write data")); + l_bError = TRUE; + break; + } + } + + //////////////////////////////////////////////////////////////////////////// + //push buffers to empty list + LOCK_ENTER(m_hCS); + + if (l_bError) + { + m_bConnected = FALSE; + l_bUpdate = TRUE; + } + + while ((l_pEl = l_cBuffers.Get_First())) + { + l_pBuffer = l_cBuffers.Get_Data(l_pEl); + + l_pBuffer->szUsed = 0; + + if (FALSE == l_bHeader) //write header if it was not write before + { + memcpy(l_pBuffer->pBuffer, + &m_cHeader, + sizeof(m_cHeader) + ); + + l_pBuffer->szUsed += sizeof(m_cHeader); + + l_bHeader = TRUE; + + m_cBuffer_Empty.Add_After(NULL, l_pBuffer); + } + else + { + m_cBuffer_Empty.Add_After(m_cBuffer_Empty.Get_Last(), l_pBuffer); + } + + l_cBuffers.Del(l_pEl, FALSE); + }//while (l_pEl = l_cBuffers.Get_First()) + + LOCK_EXIT(m_hCS); + + //////////////////////////////////////////////////////////////////////////// + //create new file + m_cFile.Close(TRUE); + + if (m_bConnected) + { + if (ECLIENT_STATUS_OK != Create_File()) + { + JOURNAL_CRITICAL(m_pLog, TM("Not possible to create file")); + + LOCK_ENTER(m_hCS); + m_bConnected = FALSE; + LOCK_EXIT(m_hCS); + + l_bUpdate = TRUE; + } + } + + if (l_bUpdate) + { + Update_Channels_Status(m_bConnected, m_dwConnection_Resets); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +//Update_Channels_Status +void CClFile::Update_Channels_Status(tBOOL i_bConnected, tUINT32 i_dwResets) +{ + sP7C_Status l_sStatus = {FALSE, 0}; + //LOCK_ENTER(m_hCS); + l_sStatus.bConnected = i_bConnected; + l_sStatus.dwResets = i_dwResets; + //LOCK_EXIT(m_hCS); + + LOCK_ENTER(m_hCS_Reg); + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus); + } + } + LOCK_EXIT(m_hCS_Reg); +}//Update_Channels_Status + + +//////////////////////////////////////////////////////////////////////////////// +//Routine +void CClFile::Routine() +{ + pAList_Cell l_pEl = NULL; + tBOOL l_bExit = FALSE; + tUINT32 l_dwSignal = MEVENT_TIME_OUT; + tUINT32 l_dwWait_TimeOut = THREAD_IDLE_TIMEOUT; + tUINT32 l_dwIteration = 0; + tBOOL l_bRoll = FALSE; + sBuffer *l_pBuffer = NULL; + tUINT32 l_uiSecond = GetSecondOfDay(); + tUINT32 l_uWriteTick = GetTickCount(); + + while (FALSE == l_bExit) + { + l_dwSignal = m_cEvent.Wait(l_dwWait_TimeOut); + + if ( (eThreadEventHasData == l_dwSignal) //one buffer to write! + || ( (MEVENT_TIME_OUT == l_dwSignal) + && (CTicks::Difference(GetTickCount(), l_uWriteTick) > THREAD_WRITE_TIMEOUT) + ) + ) + { + l_dwWait_TimeOut = 0; + + //////////////////////////////////////////////////////////////////// + //extract buffer + LOCK_ENTER(m_hCS); + + l_pBuffer = NULL; + l_bRoll = FALSE; + + if ( (EROLLING_MEGABYTES == m_eRolling) + && (m_qwRolling_Value <= m_qwFile_Size) + ) + { + l_bRoll = TRUE; + } + else + { + l_pEl = m_cBuffer_Ready.Get_First(); + if (l_pEl) + { + l_pBuffer = m_cBuffer_Ready.Get_Data(l_pEl); + m_cBuffer_Ready.Del(l_pEl, FALSE); + } + else + { + l_pBuffer = m_pBuffer_Current; + m_pBuffer_Current = 0; + } + } + + LOCK_EXIT(m_hCS); + + //////////////////////////////////////////////////////////////////// + //writing data + if (l_pBuffer) + { + m_qwFile_Size += l_pBuffer->szUsed; + + if ( (m_bConnected) + && (l_pBuffer->szUsed > m_cFile.Write(l_pBuffer->pBuffer, + l_pBuffer->szUsed, + FALSE + ) + ) + ) + { + JOURNAL_CRITICAL(m_pLog, TM("Not possible to write data")); + + Update_Channels_Status(FALSE, m_dwConnection_Resets); + + LOCK_ENTER(m_hCS); + m_bConnected = FALSE; + LOCK_EXIT(m_hCS); + } + + LOCK_ENTER(m_hCS); + l_pBuffer->szUsed = 0; + m_cBuffer_Empty.Add_After(NULL, l_pBuffer); + LOCK_EXIT(m_hCS); + } + else if (l_bRoll) //rolling files + { + Roll(); + } + + l_uWriteTick = GetTickCount(); + } + else if (MEVENT_TIME_OUT == l_dwSignal) + { + l_dwWait_TimeOut = THREAD_IDLE_TIMEOUT; + } + else if (eThreadEventExit == l_dwSignal) + { + l_bExit = TRUE; + } + else if (eThreadEventDataFlush == l_dwSignal) + { + LOCK_ENTER(m_hCS); + if ( (m_pBuffer_Current) + && (m_pBuffer_Current->szUsed) + ) + { + m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), m_pBuffer_Current); + m_pBuffer_Current = NULL; + m_cEvent.Set(eThreadEventHasData); + } + LOCK_EXIT(m_hCS); + } + + + if (EROLLING_HOURS == m_eRolling) + { + if ( (0 == (l_dwIteration & 0x3F)) + && (CTicks::Difference(GetTickCount(), m_dwFile_Tick) > m_qwRolling_Value) + ) + { + Roll(); + l_uWriteTick = GetTickCount(); + } + } + else if (EROLLING_TIME == m_eRolling) + { + if (0 == (l_dwIteration & 0x3F)) + { + tUINT32 l_uiNextSecond = GetSecondOfDay(); + pAList_Cell l_pEl = NULL; + + while ((l_pEl = m_cSecondsList.Get_Next(l_pEl))) + { + tUINT32 l_uiIem = m_cSecondsList.Get_Data(l_pEl); + if ( (l_uiSecond <= l_uiIem) + && (l_uiNextSecond > l_uiIem) + ) + { + Roll(); + l_uWriteTick = GetTickCount(); + break; + } + } + + l_uiSecond = l_uiNextSecond; + } + } + + l_dwIteration++; + } +}//Comm_Routine diff --git a/p7lib/Sources/ClFile.h b/p7lib/Sources/ClFile.h new file mode 100644 index 0000000..9445153 --- /dev/null +++ b/p7lib/Sources/ClFile.h @@ -0,0 +1,151 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to file / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLFILE_H +#define CLFILE_H + +#include "IFile.h" +#include "PFile.h" + + +//////////////////////////////////////////////////////////////////////////////// +class CClFile: + public CClient +{ +protected: + struct sBuffer + { + tUINT8 *pBuffer; + size_t szUsed; + + sBuffer(size_t i_szBuffer) + { + pBuffer = (tUINT8*)malloc(i_szBuffer); + szUsed = 0; + } + + ~sBuffer() + { + if (pBuffer) + { + free(pBuffer); + pBuffer = NULL; + } + szUsed = 0; + } + }; + + enum eRolling + { + EROLLING_NONE, + EROLLING_MEGABYTES, + EROLLING_HOURS, + EROLLING_TIME + }; + +private: + tINT32 volatile m_lReject_Mem; + tINT32 volatile m_lReject_Con; + tINT32 volatile m_lReject_Int; + + CMEvent m_cEvent; + tBOOL m_bThread; + CThShell::tTHREAD m_hThread; + + CBList m_cBuffer_Empty; + CBList m_cBuffer_Ready; + sBuffer *m_pBuffer_Current; + tUINT32 m_dwBuffer_Size; + tUINT32 m_dwBuffers_Count; + CPFile m_cFile; + CWString m_pDir; + sP7File_Header m_cHeader; + eRolling m_eRolling; + tUINT64 m_qwRolling_Value; + tUINT32 m_dwFile_Tick; + tUINT64 m_qwFile_Size; + tUINT32 m_dwFiles_Max_Count; + tUINT64 m_qwFiles_Max_Size; + CBList m_cFiles; + CUintList m_cSecondsList; + tUINT32 m_dwIndex; + +public: + CClFile(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + virtual ~CClFile(); + +private: + eClient_Status Init_Base(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + + eClient_Status Init_Pool(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + + eClient_Status Init_File(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + + eClient_Status Init_Thread(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + + eClient_Status Create_File(); + + tBOOL Parse_Rolling_Time(const tXCHAR *i_pTime); + +public: + eClient_Status Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ); + + tBOOL Get_Info(sP7C_Info *o_pInfo); + tBOOL Close(); + void Flush(); + + +private: + void Roll(); + void Update_Channels_Status(tBOOL i_bConnected, tUINT32 i_dwResets); + + static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_Routine(void *i_pContext) + { + CClFile *l_pRoutine = static_cast(i_pContext); + if (l_pRoutine) + { + l_pRoutine->Routine(); + } + + CThShell::Cleanup(); + return THSHELL_RET_OK; + } + + void Routine(); +}; + + +#endif //CLFILE_H diff --git a/p7lib/Sources/ClNull.cpp b/p7lib/Sources/ClNull.cpp new file mode 100644 index 0000000..8309616 --- /dev/null +++ b/p7lib/Sources/ClNull.cpp @@ -0,0 +1,121 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to NULL / +//////////////////////////////////////////////////////////////////////////////// + +#include "CommonClient.h" +#include "ClNull.h" + +//////////////////////////////////////////////////////////////////////////////// +//CClNull() +CClNull::CClNull(tXCHAR **i_pArgs, + tINT32 i_iCount + ) + : CClient(IP7_Client::eNull, i_pArgs, i_iCount) +{ + Init_Base(i_pArgs, i_iCount); +}//CClNull() + + +//////////////////////////////////////////////////////////////////////////////// +//~CClNull() +CClNull::~CClNull() +{ + Close(); + CClient::Unshare(); +}//~CClNull() + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Base +eClient_Status CClNull::Init_Base(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + UNUSED_ARG(i_pArgs); + UNUSED_ARG(i_iCount); + + return ECLIENT_STATUS_OK; +}//Init_Base + + +//////////////////////////////////////////////////////////////////////////////// +//Sent +eClient_Status CClNull::Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ) +{ + UNUSED_ARG(i_dwChannel_ID); + UNUSED_ARG(i_pChunks); + UNUSED_ARG(i_dwCount); + UNUSED_ARG(i_dwSize); + + return ECLIENT_STATUS_OK; +}//Sent + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Status +tBOOL CClNull::Get_Status(sP7C_Status *o_pStatus) +{ + if (NULL == o_pStatus) + { + return FALSE; + } + + o_pStatus->bConnected = TRUE; + o_pStatus->dwResets = 0; + + return TRUE; +}//Get_Status + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Info +tBOOL CClNull::Get_Info(sP7C_Info *o_pInfo) +{ + if (NULL == o_pInfo) + { + return FALSE; + } + + o_pInfo->dwReject_Mem = 0; + o_pInfo->dwReject_Con = 0; + o_pInfo->dwReject_Int = 0; + + return TRUE; +}//Get_Info + + +//////////////////////////////////////////////////////////////////////////////// +//Close +tBOOL CClNull::Close() +{ + return TRUE; +}//Close + +//////////////////////////////////////////////////////////////////////////////// +//Flush +void CClNull::Flush() +{ +}//Flush + diff --git a/p7lib/Sources/ClNull.h b/p7lib/Sources/ClNull.h new file mode 100644 index 0000000..d993068 --- /dev/null +++ b/p7lib/Sources/ClNull.h @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to NULL / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLNULL_H +#define CLNULL_H + +class CClNull: + public CClient +{ +public: + CClNull(tXCHAR **i_pArgs, + tINT32 i_iCount + ); + virtual ~CClNull(); + +private: + eClient_Status Init_Base(tXCHAR **i_pArgs, tINT32 i_iCount); + +public: + eClient_Status Get_Status() + { + return ECLIENT_STATUS_OK; + } + + eClient_Status Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ); + + tBOOL Get_Status(sP7C_Status *o_pStatus); + tBOOL Get_Info(sP7C_Info *o_pInfo); + tBOOL Close(); + void Flush(); + +}; + + +#endif //CLNULL_H diff --git a/p7lib/Sources/ClText.cpp b/p7lib/Sources/ClText.cpp new file mode 100644 index 0000000..45997cc --- /dev/null +++ b/p7lib/Sources/ClText.cpp @@ -0,0 +1,2083 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to format data into text format / +//////////////////////////////////////////////////////////////////////////////// + +#include "CommonClient.h" +#include "ClText.h" + +//allow to see dump of memory leaks at the end of test in VS debug output +//#define _CRTDBG_MAP_ALLOC +//#include +//#ifdef _DEBUG +//#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) +//#define new DEBUG_NEW +//#endif + +#define THREAD_IDLE_TIMEOUT (100) +#define FREE_DATA_WAIT_TIMEOUT (100) + +enum eThreadsEvents +{ + eThreadEventExit = MEVENT_SIGNAL_0, + eThreadEventHasData, + eThreadEventDataFlush, + eThreadEventsCount = 3 +}; + +#define DATA_FREE_SIGNAL (MEVENT_SIGNAL_0) + +#define MIN_BUFFER_SIZE (16384) +#define MAX_BUFFER_SIZE (131072) +#define MIN_BUFFERS_COUNT (3) + +#define DEF_POOL_SIZE (MAX_BUFFER_SIZE * 16) +#define MIN_POOL_SIZE (MIN_BUFFER_SIZE * MIN_BUFFERS_COUNT) +#define TRACE_TEXT_LENGTH (0x1000) + +#define TAIL_SIZE(iBuffer) (m_dwBuffer_Size - (tUINT32)iBuffer->szUsed) + +#define TIME_HRS_100NS 36000000000ull +#define TIME_MIN_100NS 600000000ull +#define TIME_SEC_100NS 10000000ull +#define TIME_MSC_100NS 10000ull + +#ifndef min + #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#if !defined(MAXUINT64) + #define MAXUINT64 ((tUINT64)~((tUINT64)0)) +#endif + +#define REALLOC_MESSAGE(i_szValue, i_pClient)\ +if ((i_szValue + 256) >= (i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg)))\ +{\ + size_t l_szNew = i_pClient->m_szMsg + i_szValue + 256;\ + tXCHAR *l_pNew = (tXCHAR *)realloc(i_pClient->m_pMsg, l_szNew * sizeof(tXCHAR));\ + if (l_pNew)\ + {\ + i_pClient->m_pMsgCur = l_pNew + (i_pClient->m_pMsgCur - i_pClient->m_pMsg);\ + i_pClient->m_pMsg = l_pNew;\ + i_pClient->m_szMsg = l_szNew;\ + }\ +}\ + + +struct sField +{ + const tXCHAR *pField; + CClText::fnFormat pFormat; +}; + +static const sField g_pFields[] = +{ + { CLIENT_FMT_CHANNEL, CClText::FormatChannel }, + { CLIENT_FMT_MSG_ID, CClText::FormatMessageId }, + { CLIENT_FMT_MSG_INDEX, CClText::FormatMessageIndex }, + { CLIENT_FMT_TIME_FULL, CClText::FormatTimeFull }, + { CLIENT_FMT_TIME_MEDIUM, CClText::FormatTimeMedium }, + { CLIENT_FMT_TIME_SHORT, CClText::FormatTimeShort }, + { CLIENT_FMT_TIME_DIFF, CClText::FormatTimeDiff }, + { CLIENT_FMT_TIME_COUNT, CClText::FormatTimeCount }, + { CLIENT_FMT_LEVEL, CClText::FormatLevel }, + { CLIENT_FMT_THREAD_ID, CClText::FormatThreadId }, + { CLIENT_FMT_THREAD_NAME, CClText::FormatThreadName }, + { CLIENT_FMT_CPU_CORE, CClText::FormatCpuCore }, + { CLIENT_FMT_MODULE_ID, CClText::FormatModuleId }, + { CLIENT_FMT_MODULE_NAME, CClText::FormatModuleName }, + { CLIENT_FMT_FILE_FULL, CClText::FormatFilePath }, + { CLIENT_FMT_FILE_SHORT, CClText::FormatFileName }, + { CLIENT_FMT_FILE_LINE, CClText::FormatFileLine }, + { CLIENT_FMT_FUNCTION, CClText::FormatFunction }, + { CLIENT_FMT_MSG, CClText::FormatMsg } +}; + + +#define LEVEL_TEXT_LENGTH (5) +static const tXCHAR *g_pLevel[EP7TRACE_LEVEL_COUNT] = +{ + TM("TRACE"), + TM("DEBUG"), + TM("INFO "), + TM("WARN."), + TM("ERROR"), + TM("PANIC") +}; + + +//////////////////////////////////////////////////////////////////////////////// +CClText::fnFormat GetFormatFunction(const tXCHAR *i_pField) +{ + if (!*i_pField) //at least 2 chars + { + return NULL; + } + + for (size_t l_szI = 0; l_szI < LENGTH(g_pFields); l_szI++) + { + #ifdef UTF8_ENCODING + if ((*(tUINT16*)i_pField) == (*(tUINT16*)g_pFields[l_szI].pField)) + #else + if ((*(tUINT32*)i_pField) == (*(tUINT32*)g_pFields[l_szI].pField)) + #endif + { + return g_pFields[l_szI].pFormat; + } + } + return NULL; +} + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// sTraceDescEx +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +sTraceDescEx::sTraceDescEx(const sP7Trace_Format *i_pFormat, + CFormatter::sBuffer *i_pBuffer, + tBOOL i_bBigEndian + ) + : sTraceDesc() + , pBuffer(NULL) + , dwSize(0) + , pFormat(NULL) + , pArgs(NULL) + , dwArgsLen(0) +{ + size_t l_szLen = 0; + + if (i_pFormat) + { + dwSize = i_pFormat->sCommon.dwSize; + pBuffer = (tUINT8*)malloc(dwSize); + } + + if (pBuffer) + { + memcpy(pBuffer, i_pFormat, dwSize); + wLine = i_pFormat->wLine; + dwArgsLen = i_pFormat->wArgs_Len; + dwModuleID = i_pFormat->wModuleID; + pArgs = (sP7Trace_Arg*)(pBuffer + sizeof(sP7Trace_Format)); + + #ifdef UTF8_ENCODING + tWCHAR *l_pFormat = (tWCHAR *)(pArgs + dwArgsLen); + size_t l_szUtf8Chars = 0; + size_t l_szUtf8Bytes = 0; + l_szLen = Get_UTF8_Stat(l_pFormat, l_szUtf8Bytes, l_szUtf8Chars); + l_szUtf8Bytes += 8; + + pFormat = (tXCHAR*)malloc(l_szUtf8Bytes * sizeof(tXCHAR)); + Convert_UTF16_To_UTF8(l_pFormat, (tACHAR*)pFormat, l_szUtf8Bytes); + + pFilePath = (char*)(l_pFormat + l_szLen + 1); + szFilePath = strlen(pFilePath); + pFunction = (char*)(pFilePath + szFilePath + 1); + szFunction = strlen(pFunction); + #else + char *l_pFilePath; + char *l_pFunction; + pFormat = (tXCHAR *)(pArgs + dwArgsLen); + l_szLen = PStrLen(pFormat); + l_pFilePath = (char*)(pFormat + l_szLen + 1); + szFilePath = strlen(l_pFilePath); + l_pFunction = (char*)(l_pFilePath + szFilePath + 1); + szFunction = strlen(l_pFunction); + pFilePath = (tXCHAR*)malloc((szFilePath + 16)*sizeof(tXCHAR)); + pFunction = (tXCHAR*)malloc((szFunction + 16)*sizeof(tXCHAR)); + Convert_UTF8_To_UTF16(l_pFilePath, pFilePath, (tUINT32)szFilePath + 1); + Convert_UTF8_To_UTF16(l_pFunction, pFunction, (tUINT32)szFunction + 1); + #endif + + if ( (pFileName = PStrrChr(pFilePath, TM('\\'))) + || (pFileName = PStrrChr(pFilePath, TM('/'))) + ) + { + pFileName ++; + } + else + { + pFileName = pFilePath; + }; + + szFileName = PStrLen(pFileName); + + pFormatter = new CFormatter(pFormat, pArgs, (size_t)dwArgsLen, i_pBuffer); + + if (i_bBigEndian) + { + pFormatter->EnableBigEndian(); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +sTraceDescEx::~sTraceDescEx() +{ + if (pBuffer) + { + free(pBuffer); + pBuffer = NULL; + } + + if (pFormatter) + { + delete pFormatter; + pFormatter = NULL; + } + +#ifdef UTF8_ENCODING + if (pFormat) + { + free(pFormat); + pFormat = NULL; + } +#else + if (pFilePath) + { + free(pFilePath); + } + if (pFunction) + { + free(pFunction); + } + pFilePath = NULL; + pFunction = NULL; + pFileName = NULL; +#endif +} + + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// CTxtChannel +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//CTxtChannel() +CTxtChannel::CTxtChannel(const sP7Trace_Info *i_pInfo, tBOOL i_bBig_Endian) + : m_qwStreamTime(0ull) + , m_qwTimer_Value(i_pInfo->qwTimer_Value) + , m_qwTimer_Frequency(i_pInfo->qwTimer_Frequency) + , m_qwFlags(i_pInfo->qwFlags) + , m_pText(NULL) + , m_szText(TRACE_TEXT_LENGTH) + , m_qwTimeLast(i_pInfo->qwTimer_Value) + , m_szName(0) + , m_pBuffer(NULL) + , m_bBig_Endian(i_bBig_Endian) +{ +#ifdef UTF8_ENCODING + Convert_UTF16_To_UTF8(i_pInfo->pName, (tACHAR*)m_pName, P7TRACE_NAME_LENGTH); +#else + PStrCpy(m_pName, P7TRACE_NAME_LENGTH, (const wchar_t*)i_pInfo->pName); +#endif + + m_pBuffer = new CFormatter::sBuffer(4096); + + m_szName = PStrLen(m_pName); + + m_qwStreamTime = (tUINT64)i_pInfo->dwTime_Lo + (((tUINT64)i_pInfo->dwTime_Hi) << 32); + + //fill list by empty elements, prepare data ... + for (tUINT32 l_dwIDX = 0; l_dwIDX < 1536; l_dwIDX ++) + { + m_cDesc.Add_After(NULL, NULL); + } + //trick to build index, this is new list and index is not build + //when we try to access to element by index - we create internal index + //table + m_cDesc[0]; + + //fill list by empty elements, prepare data ... + for (tUINT32 l_dwIDX = 0; l_dwIDX < 128; l_dwIDX ++) + { + m_cModules.Add_After(NULL, NULL); + } + + //trick to build index, this is new list and index is not build + //when we try to access to element by index - we create internal index + //table + m_cModules[0]; + + m_pText = (tXCHAR*)malloc(m_szText * sizeof(tXCHAR)); +}//CTxtChannel() + +//////////////////////////////////////////////////////////////////////////////// +//~CTxtChannel() +CTxtChannel::~CTxtChannel() +{ + m_cDesc.Clear(TRUE); + m_cModules.Clear(TRUE); + m_cThreads.Clear(); + + if (m_pText) + { + free(m_pText); + m_pText = NULL; + } + + if (m_pBuffer) + { + m_pBuffer->Release(); + m_pBuffer = NULL; + } +}//~CTxtChannel() + + +//////////////////////////////////////////////////////////////////////////////// +//PutFormat +void CTxtChannel::PutFormat(const sP7Trace_Format *i_pDesc) +{ + //fill by empty elements if ID is larger than elements count + while (m_cDesc.Count() <= i_pDesc->wID) + { + m_cDesc.Add_After(m_cDesc.Get_Last(), NULL); + } + + if (NULL == m_cDesc[i_pDesc->wID]) + { + m_cDesc.Put_Data(m_cDesc.Get_ByIndex(i_pDesc->wID), + new sTraceDescEx(i_pDesc, m_pBuffer, m_bBig_Endian), + TRUE + ); + } +}//PutFormat + + +//////////////////////////////////////////////////////////////////////////////// +//PutModule +void CTxtChannel::PutModule(const sP7Trace_Module *i_pMod) +{ + //fill by empty elements if ID is larger than elements count + while (m_cModules.Count() <= i_pMod->wModuleID) + { + m_cModules.Add_After(m_cModules.Get_Last(), NULL); + } + + if (NULL == m_cModules[i_pMod->wModuleID]) + { + sP7TraceMod *l_pMod = new sP7TraceMod(); + l_pMod->eVerbosity = i_pMod->eVerbosity; + #ifdef UTF8_ENCODING + memcpy(l_pMod->pName, i_pMod->pName, P7TRACE_MODULE_NAME_LENGTH); + #else + Convert_UTF8_To_UTF16(i_pMod->pName, + (tWCHAR*)l_pMod->pName, + P7TRACE_MODULE_NAME_LENGTH + ); + #endif + l_pMod->szName = PStrLen(l_pMod->pName); + + m_cModules.Put_Data(m_cModules.Get_ByIndex(i_pMod->wModuleID), l_pMod, TRUE); + } +}//PutModule + + +//////////////////////////////////////////////////////////////////////////////// +//RegisterThread +void CTxtChannel::RegisterThread(const sP7Trace_Thread_Start *i_pStart) +{ + sThread *l_pThread = new sThread(); + l_pThread->dwThreadID = i_pStart->dwThreadID; + l_pThread->qwStart = i_pStart->qwTimer; + l_pThread->qwStop = MAXUINT64; + +#ifdef UTF8_ENCODING + memcpy(l_pThread->pName, i_pStart->pName, P7TRACE_THREAD_NAME_LENGTH); +#else + Convert_UTF8_To_UTF16(i_pStart->pName, + (tWCHAR*)l_pThread->pName, + P7TRACE_THREAD_NAME_LENGTH + ); +#endif + + l_pThread->szName = PStrLen(l_pThread->pName); + + sRbThread *l_pRbCurr = m_cThreads.Find(l_pThread->dwThreadID); + + if (l_pRbCurr) + { + sRbThread *l_pRbPrev = NULL; + while (l_pRbCurr) + { + if (l_pThread->qwStart > l_pRbCurr->pThread->qwStart) + { + sRbThread *l_pRbNew = NULL; + if (l_pRbPrev) + { + l_pRbNew = new sRbThread(l_pThread, l_pRbCurr); + l_pRbPrev->pNext = l_pRbNew; + } + else //if it is first element in queue + { + l_pRbNew = new sRbThread(NULL, NULL); + //Move current (first) to new one + *l_pRbNew = *l_pRbCurr; + //Set current (first) with new data + l_pRbCurr->pThread = l_pThread; + l_pRbCurr->pNext = l_pRbNew; + //initialize pointer to new one + l_pRbNew = l_pRbCurr; + } + + if ( (l_pRbNew->pNext) + && (MAXUINT64 == l_pRbNew->pNext->pThread->qwStop) + ) + { + l_pRbNew->pNext->pThread->qwStop = l_pRbNew->pThread->qwStart - 1ull; + } + + break; + } + else if (l_pThread->qwStart == l_pRbCurr->pThread->qwStart) + { + //repeat !!! + //l_pRbCurr->pThread->qwStop = i_pThread->qwStop; + delete l_pThread; + break; + } + else + { + l_pRbPrev = l_pRbCurr; + l_pRbCurr = l_pRbCurr->pNext; + } + } + } + else //not found + { + m_cThreads.Push(new sRbThread(l_pThread, NULL), l_pThread->dwThreadID); + } +}//RegisterThread + + +//////////////////////////////////////////////////////////////////////////////// +//UnregisterThread +void CTxtChannel::UnregisterThread(const sP7Trace_Thread_Stop *i_pStop) +{ + sRbThread *l_pRbCurr = m_cThreads.Find(i_pStop->dwThreadID); + + if ( (l_pRbCurr) + && (l_pRbCurr->pThread) + ) + { + l_pRbCurr->pThread->qwStop = i_pStop->qwTimer; + } +}//UnregisterThread + + +//////////////////////////////////////////////////////////////////////////////// +//Format() +tBOOL CTxtChannel::Format(sP7Trace_Data *i_pData, CClTextSink::sLog &o_rLog) +{ + tBOOL l_bReturn = TRUE; + sTraceDescEx *l_pDesc = NULL; + tUINT8 *l_pValues = ((tUINT8*)i_pData) + sizeof(sP7Trace_Data); + sRbThread *l_pRbThread = NULL; + int l_iCount = 0; + tUINT8 *l_pExt = (tUINT8*)i_pData + i_pData->sCommon.dwSize - 1; + tUINT8 l_bCount = l_pExt[0]; + tDOUBLE l_dbTimeDiff= 0.0; + + l_pDesc = m_cDesc[i_pData->wID]; + + if ( (NULL == l_pDesc) + || (!m_pText) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + o_rLog.dwModuleID = 0u; + + while (l_bCount--) //Parse extensions, there is no need to check the presence, it is always here because of using locally + { + --l_pExt; + if (EP7TRACE_EXT_MODULE_ID == l_pExt[0]) + { + l_pExt -= 2; + o_rLog.dwModuleID = *(tUINT16*)l_pExt; + --l_pExt; + } + } + + while (!l_iCount) + { + l_iCount = l_pDesc->pFormatter->Format(m_pText, m_szText, l_pValues); + + if ( (l_iCount < 0) + || ((size_t)(l_iCount + 1) >= m_szText) + ) + { + free(m_pText); + m_szText *= 2; + m_pText = (tXCHAR*)malloc(m_szText * sizeof(tXCHAR)); + l_iCount = 0; + if (!m_pText) + { + break; + } + } + } + + o_rLog.pChannel = m_pName; + o_rLog.szChannel = m_szName; + o_rLog.szMessage = l_iCount; + + //Get thread name if it is ... + o_rLog.pThreadName = TM("Unkn."); + o_rLog.szThreadName = 5; + + l_pRbThread = m_cThreads.Find(i_pData->dwThreadID); + + if (l_pRbThread) + { + while (l_pRbThread) + { + if ( (i_pData->qwTimer >= l_pRbThread->pThread->qwStart) + && (i_pData->qwTimer <= l_pRbThread->pThread->qwStop) + ) + { + o_rLog.pThreadName = l_pRbThread->pThread->pName; + o_rLog.szThreadName = l_pRbThread->pThread->szName; + break; + } + + l_pRbThread = l_pRbThread->pNext; + } + } + + if (m_cModules[o_rLog.dwModuleID]) + { + o_rLog.pModuleName = m_cModules[o_rLog.dwModuleID]->pName; + o_rLog.szModuleName = m_cModules[o_rLog.dwModuleID]->szName; + } + else + { + o_rLog.pModuleName = TM("Unkn."); + o_rLog.szModuleName = 5; + } + + l_dbTimeDiff = (((tDOUBLE)i_pData->qwTimer - (tDOUBLE)m_qwTimer_Value) * (tDOUBLE)TIME_SEC_100NS) / (tDOUBLE)m_qwTimer_Frequency; + + UnpackLocalTime(m_qwStreamTime + (tUINT64)l_dbTimeDiff, + o_rLog.dwYear, + o_rLog.dwMonth, + o_rLog.dwDay, + o_rLog.dwHour, + o_rLog.dwMinutes, + o_rLog.dwSeconds, + o_rLog.dwMilliseconds, + o_rLog.dwMicroseconds, + o_rLog.dwNanoseconds + ); + + + o_rLog.qwRawTime = m_qwStreamTime + (tUINT64)l_dbTimeDiff; + o_rLog.qwRawTimeOffset = (tUINT64)l_dbTimeDiff; + o_rLog.pChannel = m_pName; + o_rLog.qwIndex = i_pData->dwSequence; + o_rLog.dwId = i_pData->wID; + o_rLog.eLevel = (eP7Trace_Level)i_pData->bLevel; + o_rLog.dwCpuCore = i_pData->bProcessor; + o_rLog.dwThreadId = i_pData->dwThreadID; + o_rLog.pDesc = static_cast(l_pDesc); + o_rLog.pMessage = m_pText; + + m_qwTimeLast = i_pData->qwTimer; + +l_lblExit: + return l_bReturn; +}//Format() + + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// CClText +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +//CClText() +CClText::CClText(tXCHAR **i_pArgs, tINT32 i_iCount) + : CClient(IP7_Client::eText, i_pArgs, i_iCount) + , m_lReject_Mem(0) + , m_lReject_Con(0) + , m_lReject_Int(0) + , m_bThread(FALSE) + , m_hThread(0) //NULL + , m_bNoData(FALSE) + , m_pBuffer_Current(0) + , m_dwBuffer_Size(0) + , m_dwBuffers_Count(0) + , m_bBig_Endian(FALSE) + , m_pChunk(0) + , m_szChunkMax(0) + , m_szChunkUsd(0) + , m_pFormat(NULL) + , m_pMsg(NULL) + , m_pMsgCur(NULL) + , m_szMsg(0) + , m_pSink(NULL) + , m_bSinkExternal(FALSE) +{ + memset(m_pTxtCh, 0, sizeof(m_pTxtCh)); + + //1. base init + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Base(i_pArgs, i_iCount); + } + + //2. Initialize Pool + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Pool(i_pArgs, i_iCount); + } + + //3. Initialize backend + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Backend(i_pArgs, i_iCount); + } + + //4. Initialize variables + if (ECLIENT_STATUS_OK == m_eStatus) + { + m_eStatus = Init_Thread(i_pArgs, i_iCount); + } + + //5. Initialize crash handler + if (ECLIENT_STATUS_OK == m_eStatus) + { + Init_Crash_Handler(i_pArgs, i_iCount); + } +}//CClText() + + +//////////////////////////////////////////////////////////////////////////////// +//~CClText() +CClText::~CClText() +{ + Uninit_Crash_Handler(); + + Close(); + + if (m_pSink) + { + if (!m_bSinkExternal) + { + delete m_pSink; + } + m_pSink = NULL; + } + + if (m_pBuffer_Current) + { + delete m_pBuffer_Current; + m_pBuffer_Current = NULL; + } + + if (m_pChunk) + { + free(m_pChunk); + m_pChunk = NULL; + } + + m_szChunkMax = 0; + + m_cBuffer_Empty.Clear(TRUE); + m_cBuffer_Ready.Clear(TRUE); + + for (size_t l_szI = 0; l_szI < LENGTH(m_pChannels); l_szI++) + { + if (m_pTxtCh[l_szI]) + { + delete m_pTxtCh[l_szI]; + m_pTxtCh[l_szI] = NULL; + } + } + + while (m_pFormat) + { + sFormat *l_pTmp = m_pFormat; + m_pFormat = m_pFormat->pNext; + + if (l_pTmp->pStr) + { + free(l_pTmp->pStr); + l_pTmp->pStr = NULL; + } + + free(l_pTmp); + } + + CClient::Unshare(); + + + if (m_pMsg) + { + free(m_pMsg); + m_pMsg = NULL; + } + + m_pMsgCur = NULL; + + //printf("Reject mem:%d, con:%d, init:%d\n", m_lReject_Mem, m_lReject_Con, m_lReject_Int); +}//~CClText() + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Base +eClient_Status CClText::Init_Base(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_WRONG_FORMAT; + tXCHAR *l_pFormatStr = NULL; + tUINT32 l_dwEndian = 0x1; + tUINT8 l_bLittleE = *(tUINT8*)&l_dwEndian; + + if (!l_bLittleE) + { + m_bBig_Endian = TRUE; + } + + //////////////////////////////////////////////////////////////////////////// + //getting pool size + l_pFormatStr = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_FORMAT); + if (l_pFormatStr) + { + l_eReturn = ParseFormat(l_pFormatStr); + } + + if (ECLIENT_STATUS_OK != l_eReturn) + { + l_eReturn = ParseFormat(TM("%") CLIENT_FMT_CHANNEL TM(" ") + TM("#%") CLIENT_FMT_MSG_INDEX TM(" ") + TM("[%") CLIENT_FMT_TIME_FULL TM("] ") + TM("%") CLIENT_FMT_LEVEL TM(" ") + TM("Tr:#%") CLIENT_FMT_THREAD_ID TM(":") + TM("%") CLIENT_FMT_THREAD_NAME TM(" ") + TM("CPU:%") CLIENT_FMT_CPU_CORE TM(" ") + TM("Md:%") CLIENT_FMT_MODULE_NAME TM(" ") + TM("{%") CLIENT_FMT_FILE_SHORT TM(":") + TM("%") CLIENT_FMT_FILE_LINE TM(":") + TM("%") CLIENT_FMT_FUNCTION TM("} ") + TM("%") CLIENT_FMT_MSG + ); + } + + return l_eReturn; +}//Init_Base + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Pool +eClient_Status CClText::Init_Pool(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tXCHAR *l_pArg_Value = NULL; + tUINT32 l_dwPool_Size = DEF_POOL_SIZE; + tUINT32 l_dwBuffer_Size = MAX_BUFFER_SIZE * 2; + tUINT32 l_dwBuffers_Count = 0; + + //////////////////////////////////////////////////////////////////////////// + //getting pool size + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_POOL_SIZE); + if (l_pArg_Value) + { + l_dwPool_Size = 1024 * (tUINT32)PStrToInt(l_pArg_Value); + + if (MIN_POOL_SIZE > l_dwPool_Size) + { + l_dwPool_Size = MIN_POOL_SIZE; + } + } + + //////////////////////////////////////////////////////////////////////////// + //calculate buffer size and buffers count + //Starting from largest buffer size trying to calculate how much buffers we + //can allocate, is amount is smaller than minimum - device buffer size by 2 + //and repeat procedure + while (l_dwBuffers_Count < MIN_BUFFERS_COUNT) + { + l_dwBuffer_Size /= 2; + l_dwBuffers_Count = l_dwPool_Size / l_dwBuffer_Size; + } + + if ( (MIN_BUFFER_SIZE > l_dwBuffer_Size) + || (MIN_BUFFERS_COUNT > l_dwBuffers_Count) + ) + { + P7_Set_Last_Error(eP7_Error_UserSettings); + + JOURNAL_ERROR(m_pLog, + TM("Pool: Memory calculation error, buffer size = %d, buffers count = %d"), + l_dwBuffer_Size, + l_dwBuffers_Count + ); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //allocate buffers + m_dwBuffer_Size = l_dwBuffer_Size; + m_dwBuffers_Count = l_dwBuffers_Count; + + for (tUINT32 l_dwI = 0; l_dwI < m_dwBuffers_Count; l_dwI++) + { + sBuffer *l_pBuffer = new sBuffer(m_dwBuffer_Size); + if (l_pBuffer) + { + m_cBuffer_Empty.Add_After(NULL, l_pBuffer); + } + else + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + JOURNAL_ERROR(m_pLog, TM("Pool: Memory allocation failed")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + goto l_lblExit; + } + } + + m_szChunkMax = 4096; + m_pChunk = (tUINT8*)malloc(m_szChunkMax); + if (NULL == m_pChunk) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + JOURNAL_ERROR(m_pLog, TM("Pool: Memory fragment allocation failed")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + goto l_lblExit; + } + + + m_szMsg = 4096; + m_pMsg = (tXCHAR*)malloc(m_szMsg * sizeof(tXCHAR)); + m_pMsgCur = m_pMsg; + + if (NULL == m_pMsg) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + JOURNAL_ERROR(m_pLog, TM("Pool: Memory message allocation failed")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + goto l_lblExit; + } + +l_lblExit: + return l_eReturn; +}//Init_Pool + + +//////////////////////////////////////////////////////////////////////////////// +//Init_File +eClient_Status CClText::Init_Backend(tXCHAR **i_pArgs, tINT32 i_iCount) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tXCHAR *l_pSink = NULL; + + //////////////////////////////////////////////////////////////////////////// + //getting pool size + l_pSink = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_SINK); + if (l_pSink) + { + if (0 == PStrICmp(l_pSink, CLIENT_SINK_CONSOLE)) + { + m_pSink = static_cast(new CClTextConsole()); + } + else if (0 == PStrICmp(l_pSink, CLIENT_SINK_FILE_TXT)) + { + m_pSink = static_cast(new CClTextFile()); + } + else if (0 == PStrICmp(l_pSink, CLIENT_SINK_SYSLOG)) + { + m_pSink = static_cast(new CClTextSyslog()); + } + //WARNING: this code is dedicated only for self-testing. + // USE THIS OPTION ONLY ON YOUR OWN RISK! + else if (0 == PStrICmp(l_pSink, TM("ExternalSinc"))) + { + l_pSink = Get_Argument_Text_Value(i_pArgs, i_iCount, (tXCHAR*)TM("/P7.ExtAddr=")); + + if (l_pSink) + { + tUINT64 l_qwAddr = 0; + PStrScan(l_pSink, TM("%llX"), &l_qwAddr); + void *l_pAddr = (void*)l_qwAddr; + m_pSink = static_cast(l_pAddr); + m_bSinkExternal = TRUE; + } + } + } + + if (!m_pSink) + { + m_pSink = static_cast(new CClTextConsole()); + } + + if (m_pSink) + { + l_eReturn = m_pSink->Initialize(i_pArgs, i_iCount); + } + + return l_eReturn; +}//Init_File + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Thread +eClient_Status CClText::Init_Thread(tXCHAR **i_pArgs, + tINT32 i_iCount + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + + UNUSED_ARG(i_pArgs); + UNUSED_ARG(i_iCount); + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == m_cEvThread.Init(eThreadEventsCount, EMEVENT_SINGLE_AUTO, EMEVENT_MULTI, EMEVENT_SINGLE_AUTO)) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !")); + } + + if (FALSE == m_cEvData.Init(1, EMEVENT_SINGLE_AUTO)) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Exit event wasn't created !")); + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (FALSE == CThShell::Create(&Static_Routine, + this, + &m_hThread, + TM("P7:Comm") + ) + ) + { + P7_Set_Last_Error(eP7_Error_OS); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + JOURNAL_ERROR(m_pLog, TM("Communication thread wasn't created !")); + } + else + { + m_bThread = TRUE; + } + } + + return l_eReturn; +}//Init_Thread + + +//////////////////////////////////////////////////////////////////////////////// +//ParseFormat +eClient_Status CClText::ParseFormat(const tXCHAR *i_pFormat) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + const tXCHAR *l_pCursor = NULL; + + l_pCursor = i_pFormat; + + while (*l_pCursor) + { + if (TM('%') == *l_pCursor) + { + fnFormat l_pFn = GetFormatFunction(l_pCursor + 1); + if (l_pFn) + { + if (AddFormatNode(i_pFormat, l_pCursor - i_pFormat, l_pFn)) + { + l_eReturn = ECLIENT_STATUS_OK; + l_pCursor += 2; + i_pFormat = l_pCursor+ 1; + } + else + { + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + break; + } + } + } + + l_pCursor ++; + } + + if ( (ECLIENT_STATUS_OK == l_eReturn) + && (*i_pFormat) + ) + { + if (!AddFormatNode(i_pFormat, l_pCursor - i_pFormat, NULL)) + { + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + if (!m_pFormat) + { + l_eReturn = ECLIENT_STATUS_WRONG_FORMAT; + } + else + { + sFormat *l_pFormat = m_pFormat; + l_eReturn = ECLIENT_STATUS_WRONG_FORMAT; + while (l_pFormat) + { + if (l_pFormat->pFormat) + { + l_eReturn = ECLIENT_STATUS_OK; + break; + } + + l_pFormat = l_pFormat->pNext; + } + } + } + + return l_eReturn; +} + +//////////////////////////////////////////////////////////////////////////////// +//AddFormatNode +CClText::sFormat *CClText::AddFormatNode(const tXCHAR *i_pPrefix, size_t i_szPrefix, fnFormat i_pFn) +{ + sFormat *l_pReturn = (sFormat*)malloc(sizeof(sFormat)); + + if (!l_pReturn) + { + return l_pReturn; + } + + memset(l_pReturn, 0, sizeof(sFormat)); + + if (!m_pFormat) + { + m_pFormat = l_pReturn; + } + else + { + sFormat *l_pNext = m_pFormat; + while (l_pNext->pNext) { l_pNext = l_pNext->pNext; } + l_pNext->pNext = l_pReturn; + } + + if (i_szPrefix) + { + l_pReturn->pStr = (tXCHAR*)malloc((i_szPrefix + 1) * sizeof(tXCHAR)); + if (l_pReturn->pStr) + { + memcpy(l_pReturn->pStr, i_pPrefix, i_szPrefix * sizeof(tXCHAR)); + l_pReturn->pStr[i_szPrefix] = 0; + l_pReturn->szStr = i_szPrefix; + } + } + + l_pReturn->pFormat = i_pFn; + return l_pReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +//Sent +eClient_Status CClText::Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + sH_User_Data l_sHeader = {i_dwSize + (tUINT32)sizeof(l_sHeader), i_dwChannel_ID}; + sP7C_Data_Chunk l_sHeader_Chunk = {&l_sHeader, (tUINT32)sizeof(l_sHeader)}; + //Warn: variables without default values! + tBOOL l_bExit; + sP7C_Data_Chunk *l_pChunk; + tUINT32 l_dwChunk_Offs; + pAList_Cell l_pEl; + tUINT32 l_dwFree_Size; + + if (ECLIENT_STATUS_OK != m_eStatus) + { + ATOMIC_INC(&m_lReject_Int); + return m_eStatus; + } + + if ( (NULL == i_pChunks) + || (0 >= i_dwCount) + || (USER_PACKET_MAX_SIZE <= l_sHeader.dwSize) + || (USER_PACKET_CHANNEL_ID_MAX_SIZE <= i_dwChannel_ID) + ) + { + ATOMIC_INC(&m_lReject_Int); + return ECLIENT_STATUS_WRONG_PARAMETERS; + } + + //N.B. We do not check i_dwSize and real size of all chunks in release mode!!! +#ifdef _DEBUG + tUINT32 l_dwReal_Size = 0; + for (tUINT32 l_dwI = 0; l_dwI < i_dwCount; l_dwI ++) + { + if (i_pChunks[l_dwI].pData) + { + l_dwReal_Size += i_pChunks[l_dwI].dwSize; + } + else + { + break; + } + } + + if (l_dwReal_Size != i_dwSize) + { + ATOMIC_INC(&m_lReject_Int); + return ECLIENT_STATUS_WRONG_PARAMETERS; + } +#endif + + LOCK_ENTER(m_hCS); + + if (FALSE == m_bConnected) + { + l_eReturn = ECLIENT_STATUS_OFF; + ATOMIC_INC(&m_lReject_Con); + goto l_lExit; + } + + if (l_sHeader.dwSize >= (m_dwBuffer_Size * m_dwBuffers_Count)) + { + l_eReturn = ECLIENT_STATUS_NO_FREE_BUFFERS; + ATOMIC_INC(&m_lReject_Mem); + goto l_lExit; + } + + do + { + l_dwFree_Size = (m_cBuffer_Empty.Count() * m_dwBuffer_Size) + + ((m_pBuffer_Current) ? (m_dwBuffer_Size - (tUINT32)m_pBuffer_Current->szUsed) : 0); + + //if size is more than available ... + if (l_dwFree_Size < l_sHeader.dwSize) + { + m_bNoData = TRUE; + + LOCK_EXIT(m_hCS); + m_cEvData.Wait(FREE_DATA_WAIT_TIMEOUT); + LOCK_ENTER(m_hCS); + } + else + { + break; + } + } while (1); + + //because we add header as chunk + i_dwCount ++; + + l_bExit = FALSE; + l_pChunk = &l_sHeader_Chunk; //&i_pChunks[0]; + l_dwChunk_Offs = 0; + + while (FALSE == l_bExit) + { + //if packet is null we need to extract another one + if (NULL == m_pBuffer_Current) + { + l_pEl = m_cBuffer_Empty.Get_First(); + m_pBuffer_Current = m_cBuffer_Empty.Get_Data(l_pEl); + m_cBuffer_Empty.Del(l_pEl, FALSE); + } + + while ( (m_pBuffer_Current) + && (i_dwCount) + ) + { + //if packet free size is larger or equal to chunk size + if ( TAIL_SIZE(m_pBuffer_Current) >= l_pChunk->dwSize ) + { + memcpy(m_pBuffer_Current->pBuffer + m_pBuffer_Current->szUsed, + ((tUINT8*)l_pChunk->pData) + l_dwChunk_Offs, + l_pChunk->dwSize + ); + + m_pBuffer_Current->szUsed += l_pChunk->dwSize; + + //current chunk was moved, we reduce chunks amount + --i_dwCount; + + if (0 >= i_dwCount) + { + l_bExit = TRUE; + } + else + { + //we are finish with that chunk + //l_pChunk->dwSize = 0; + l_dwChunk_Offs = 0; + + if (l_pChunk == &l_sHeader_Chunk) + { + l_pChunk = &i_pChunks[0]; + } + else + { + //go to next chunk + l_pChunk ++; + } + + //if packet is filled - put it to data queue + if (0 >= TAIL_SIZE(m_pBuffer_Current)) + { + m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), + m_pBuffer_Current + ); + m_pBuffer_Current = NULL; + m_cEvThread.Set(eThreadEventHasData); + } + } + } + else //if chunk data is greater than packet free space + { + memcpy(m_pBuffer_Current->pBuffer + m_pBuffer_Current->szUsed, + ((tUINT8*)l_pChunk->pData) + l_dwChunk_Offs, + TAIL_SIZE(m_pBuffer_Current) + ); + l_dwChunk_Offs += TAIL_SIZE(m_pBuffer_Current); + l_pChunk->dwSize -= TAIL_SIZE(m_pBuffer_Current); + + m_pBuffer_Current->szUsed += TAIL_SIZE(m_pBuffer_Current); + + m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), + m_pBuffer_Current + ); + m_pBuffer_Current = NULL; + m_cEvThread.Set(eThreadEventHasData); + } + } //while ( (m_pBuffer_Current) && (i_dwCount) ) + } //while (FALSE == l_bExit) + +l_lExit: + + LOCK_EXIT(m_hCS); + + return l_eReturn; +}//Sent + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Info +tBOOL CClText::Get_Info(sP7C_Info *o_pInfo) +{ + if (NULL == o_pInfo) + { + return FALSE; + } + + LOCK_ENTER(m_hCS); + + o_pInfo->dwMem_Alloc = m_dwBuffer_Size * m_dwBuffers_Count; + o_pInfo->dwMem_Free = m_cBuffer_Empty.Count() * m_dwBuffer_Size; + o_pInfo->dwMem_Used = m_cBuffer_Ready.Count() * m_dwBuffer_Size; + + o_pInfo->dwReject_Mem = m_lReject_Mem; + o_pInfo->dwReject_Con = m_lReject_Con; + o_pInfo->dwReject_Int = m_lReject_Int; + LOCK_EXIT(m_hCS); + + return TRUE; +}//Get_Info + + +//////////////////////////////////////////////////////////////////////////////// +//Flush +tBOOL CClText::Close() +{ + tBOOL l_bStack_Trace = TRUE; + + //////////////////////////////////////////////////////////////////////////// + //notify channels about closing + sP7C_Status l_sStatus = {FALSE, 0}; + l_sStatus.bConnected = FALSE; + l_sStatus.dwResets = 0; + + if (m_bFlushChannels) + { + LOCK_ENTER(m_hCS_Reg); + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + m_pChannels[l_dwI]->On_Flush(l_dwI, &l_bStack_Trace); + m_pChannels[l_dwI]->On_Status(l_dwI, &l_sStatus); + } + } + LOCK_EXIT(m_hCS_Reg); + } + + m_cEvThread.Set(eThreadEventExit); + + if (m_bThread) + { + if (TRUE == CThShell::Close(m_hThread, 60000)) + { + m_hThread = 0;//NULL; + m_bThread = FALSE; + } + else + { + JOURNAL_CRITICAL(m_pLog, TM("Can't close file thread !")); + } + } + + //////////////////////////////////////////////////////////////////////////// + //Lock + LOCK_ENTER(m_hCS); + + pAList_Cell l_pEl = NULL; + while ((l_pEl = m_cBuffer_Ready.Get_Next(l_pEl))) + { + sBuffer *l_pBuffer = m_cBuffer_Ready.Get_Data(l_pEl); + if (l_pBuffer) + { + Parse_Buffer(l_pBuffer->pBuffer, l_pBuffer->szUsed); + } + } + + if (m_pBuffer_Current) + { + Parse_Buffer(m_pBuffer_Current->pBuffer, m_pBuffer_Current->szUsed); + } + + m_bConnected = FALSE; + + if (m_pSink) + { + if (!m_bSinkExternal) + { + delete m_pSink; + } + m_pSink = NULL; + } + + LOCK_EXIT(m_hCS); + //unlock + //////////////////////////////////////////////////////////////////////////// + + return TRUE; +}//Flush + +//////////////////////////////////////////////////////////////////////////////// +//Flush +void CClText::Flush() +{ + m_cEvThread.Set(eThreadEventDataFlush); +} + +//////////////////////////////////////////////////////////////////////////////// +//Parse_Buffer +eClient_Status CClText::Parse_Buffer(tUINT8 *i_pBuffer, size_t i_szBuffer) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + size_t l_szOffset = 0; + size_t l_szTail = 0; + while (l_szOffset < i_szBuffer) + { + l_szTail = i_szBuffer - l_szOffset; + + if (m_szChunkUsd) + { + //if header has been copied + if (sizeof(sH_User_Data) <= m_szChunkUsd) + { + if (((sH_User_Data*)m_pChunk)->dwSize > m_szChunkMax) + { + size_t l_szChunkMax = (((sH_User_Data*)m_pChunk)->dwSize + 1023) & (~1023); + tUINT8 *l_pChunk = (tUINT8*)realloc(m_pChunk, l_szChunkMax); + + if (!l_pChunk) + { + l_pChunk = (tUINT8*)malloc(l_szChunkMax); + + if ( (l_pChunk) + && (m_pChunk) + ) + { + memcpy(l_pChunk, m_pChunk, m_szChunkMax); + } + + if (m_pChunk) { free(m_pChunk); } + } + + m_pChunk = l_pChunk; + + if (m_pChunk) + { + m_szChunkMax = l_szChunkMax; + } + else + { + m_szChunkMax = 0; + } + } + + if (m_pChunk) + { + size_t l_szPacketTail = ((sH_User_Data*)m_pChunk)->dwSize - m_szChunkUsd; + + if (l_szPacketTail > l_szTail) + { + l_szPacketTail = l_szTail; + } + + memcpy(m_pChunk + m_szChunkUsd, i_pBuffer + l_szOffset, l_szPacketTail); + m_szChunkUsd += l_szPacketTail; + l_szOffset += l_szPacketTail; + + if (m_szChunkUsd == ((sH_User_Data*)m_pChunk)->dwSize) + { + l_eReturn = Parse_Packet(((sH_User_Data*)m_pChunk)->dwChannel_ID, + m_pChunk + sizeof(sH_User_Data), + ((sH_User_Data*)m_pChunk)->dwSize - sizeof(sH_User_Data)); + m_szChunkUsd = 0; + } + } + else + { + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + } + else //copy header reminder + { + size_t l_szHeaderTail = sizeof(sH_User_Data) - m_szChunkUsd; + if (l_szHeaderTail > l_szTail) + { + l_szHeaderTail = l_szTail; + } + + memcpy(m_pChunk + m_szChunkUsd, i_pBuffer + l_szOffset, l_szHeaderTail); + + m_szChunkUsd += l_szHeaderTail; + l_szOffset += l_szHeaderTail; + } + } //if buffer contains enough data for analysis + else if ( (sizeof(sH_User_Data) < l_szTail) + && (((sH_User_Data*)(i_pBuffer + l_szOffset))->dwSize <= l_szTail) + ) + { + l_eReturn = Parse_Packet(((sH_User_Data*)(i_pBuffer + l_szOffset))->dwChannel_ID, + i_pBuffer + l_szOffset + sizeof(sH_User_Data), + ((sH_User_Data*)(i_pBuffer + l_szOffset))->dwSize - sizeof(sH_User_Data) + ); + l_szOffset += ((sH_User_Data*)(i_pBuffer + l_szOffset))->dwSize; + } + else //if size of the remaining data is smaller that size of user data + { + if (l_szTail > m_szChunkMax) + { + size_t l_szChunkMax = (l_szTail + 1023) & (~1023); + tUINT8 *l_pChunk = (tUINT8*)realloc(m_pChunk, l_szChunkMax); + + if (!l_pChunk) + { + l_pChunk = (tUINT8*)malloc(l_szChunkMax); + + if ( (l_pChunk) + && (m_pChunk) + ) + { + memcpy(l_pChunk, m_pChunk, m_szChunkMax); + } + + if (m_pChunk) { free(m_pChunk); } + } + + m_pChunk = l_pChunk; + + if (m_pChunk) + { + m_szChunkMax = l_szChunkMax; + } + else + { + m_szChunkMax = 0; + } + } + + if (m_pChunk) + { + memcpy(m_pChunk, i_pBuffer + l_szOffset, l_szTail); + m_szChunkUsd = l_szTail; + l_szOffset += l_szTail; + } + else + { + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + } + + if (ECLIENT_STATUS_OK != l_eReturn) + { + break; + } + } + + return l_eReturn; +}//Parse_Buffer + + +//////////////////////////////////////////////////////////////////////////////// +//Parse_Packet +eClient_Status CClText::Parse_Packet(tUINT32 i_dwChannel, + tUINT8 *i_pPacket, + size_t i_szPacket + ) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + size_t l_szOffset = 0; + sP7Ext_Header *l_pHeader = (sP7Ext_Header *)i_pPacket; + CTxtChannel *&l_pChannel = m_pTxtCh[i_dwChannel]; + sP7Ext_Raw l_sRaw; //not initialized on purpose + + while (l_szOffset < i_szPacket) + { + l_pHeader = (sP7Ext_Header *)(i_pPacket + l_szOffset); + + //N.B.: Bits reconstruction, sP7Ext_Header is formed manually to avoid complier influence to bit fields (Using structures with + // bit fields isn't regulated by standard, every compiler is free to use own bits ordering). Headers formed in Trace or + // Telemetry may be used on different systems and they have to be unified + l_sRaw.dwBits = ((sP7Ext_Raw*)l_pHeader)->dwBits; + l_pHeader->dwType = GET_EXT_HEADER_TYPE(l_sRaw); + l_pHeader->dwSubType = GET_EXT_HEADER_SUBTYPE(l_sRaw); + l_pHeader->dwSize = GET_EXT_HEADER_SIZE(l_sRaw); + + l_szOffset += l_pHeader->dwSize; + + if (EP7USER_TYPE_TRACE != l_pHeader->dwType) + { + continue; + } + + if (l_pChannel) + { + if (EP7TRACE_TYPE_DATA == l_pHeader->dwSubType) + { + if (l_pChannel->Format((sP7Trace_Data*)l_pHeader, m_sLog)) + { + sFormat *l_pCursor = m_pFormat; + m_pMsgCur = m_pMsg; + + while (l_pCursor) + { + if (l_pCursor->pStr) + { + REALLOC_MESSAGE(l_pCursor->szStr, this); + memcpy(m_pMsgCur, l_pCursor->pStr, l_pCursor->szStr * sizeof(tXCHAR)); + m_pMsgCur += l_pCursor->szStr; + } + + if (l_pCursor->pFormat) + { + l_pCursor->pFormat(this); + } + + l_pCursor = l_pCursor->pNext; + } + *m_pMsgCur = 0; + + m_pSink->Log(m_sLog, m_pMsg, m_pMsgCur - m_pMsg); + } + } + else if (EP7TRACE_TYPE_DESC == l_pHeader->dwSubType) + { + l_pChannel->PutFormat((const sP7Trace_Format*)l_pHeader); + } + else if (EP7TRACE_TYPE_VERB == l_pHeader->dwSubType) + { + } + else if (EP7TRACE_TYPE_CLOSE == l_pHeader->dwSubType) + { + delete l_pChannel; + l_pChannel = NULL; + } + else if (EP7TRACE_TYPE_THREAD_START == l_pHeader->dwSubType) + { + l_pChannel->RegisterThread((const sP7Trace_Thread_Start*)l_pHeader); + } + else if (EP7TRACE_TYPE_THREAD_STOP == l_pHeader->dwSubType) + { + l_pChannel->UnregisterThread((const sP7Trace_Thread_Stop*)l_pHeader); + } + else if (EP7TRACE_TYPE_MODULE == l_pHeader->dwSubType) + { + l_pChannel->PutModule((const sP7Trace_Module*)l_pHeader); + } + } + else + { + if (EP7TRACE_TYPE_INFO == l_pHeader->dwSubType) + { + if (l_pChannel) + { + delete l_pChannel; + } + + l_pChannel = new CTxtChannel((const sP7Trace_Info*)l_pHeader, m_bBig_Endian); + } + else + { + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + } + } + + if (l_szOffset > i_szPacket) + { + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + + return l_eReturn; +}//Parse_Packet + + +//////////////////////////////////////////////////////////////////////////////// +//Routine +void CClText::Routine() +{ + pAList_Cell l_pEl = NULL; + tBOOL l_bExit = FALSE; + tUINT32 l_dwSignal = MEVENT_TIME_OUT; + tUINT32 l_dwRollTime = GetTickCount(); + tUINT32 l_dwDumpTime = GetTickCount(); + sBuffer *l_pBuffer = NULL; + eClient_Status l_eStatus = ECLIENT_STATUS_OK; + + while ( (FALSE == l_bExit) + && (ECLIENT_STATUS_OK == l_eStatus) + ) + { + l_dwSignal = m_cEvThread.Wait(THREAD_IDLE_TIMEOUT); + + if ( (eThreadEventHasData == l_dwSignal) //one buffer to write! + || (MEVENT_TIME_OUT == l_dwSignal) + ) + { + l_dwDumpTime = GetTickCount(); + + //////////////////////////////////////////////////////////////////// + //extract buffer + LOCK_ENTER(m_hCS); + l_pEl = m_cBuffer_Ready.Get_First(); + if (l_pEl) + { + l_pBuffer = m_cBuffer_Ready.Get_Data(l_pEl); + m_cBuffer_Ready.Del(l_pEl, FALSE); + } + else + { + l_pBuffer = m_pBuffer_Current; + m_pBuffer_Current = NULL; + } + LOCK_EXIT(m_hCS); + + //////////////////////////////////////////////////////////////////// + //format data & put data to free queue back + if (l_pBuffer) + { + l_eStatus = Parse_Buffer(l_pBuffer->pBuffer, l_pBuffer->szUsed); + + LOCK_ENTER(m_hCS); + l_pBuffer->szUsed = 0; + m_cBuffer_Empty.Add_After(NULL, l_pBuffer); + if (m_bNoData) + { + m_cEvData.Set(DATA_FREE_SIGNAL); + m_bNoData = FALSE; + } + LOCK_EXIT(m_hCS); + } + } + else if (eThreadEventExit == l_dwSignal) + { + l_bExit = TRUE; + } + else if (eThreadEventDataFlush == l_dwSignal) + { + LOCK_ENTER(m_hCS); + if ( (m_pBuffer_Current) + && (m_pBuffer_Current->szUsed) + ) + { + m_cBuffer_Ready.Add_After(m_cBuffer_Ready.Get_Last(), m_pBuffer_Current); + m_pBuffer_Current = NULL; + m_cEvThread.Set(eThreadEventHasData); + } + LOCK_EXIT(m_hCS); + } + + + if (m_pSink) + { + if (CTicks::Difference(GetTickCount(), l_dwRollTime) > 60000) //1 minute + { + m_pSink->TryRoll(); + l_dwRollTime = GetTickCount(); + } + + if (CTicks::Difference(GetTickCount(), l_dwDumpTime) > 1000) //1 second + { + m_pSink->DumpBuffers(); + l_dwDumpTime = GetTickCount(); + } + } + } +}//Comm_Routine + + +//////////////////////////////////////////////////////////////////////////////// +//FormatChannel +void CClText::FormatChannel(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.szChannel + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, i_pClient->m_sLog.pChannel, i_pClient->m_sLog.szChannel * sizeof(tXCHAR)); + i_pClient->m_pMsgCur += i_pClient->m_sLog.szChannel; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatMessageId +void CClText::FormatMessageId(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%04d"), + i_pClient->m_sLog.dwId + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatMessageIndex +void CClText::FormatMessageIndex(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%04lld"), + i_pClient->m_sLog.qwIndex + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatTimeFull +void CClText::FormatTimeFull(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%02d.%02d.%04d %02d:%02d:%02d.%03d'%03d\"%d"), + i_pClient->m_sLog.dwDay, + i_pClient->m_sLog.dwMonth, + i_pClient->m_sLog.dwYear, + i_pClient->m_sLog.dwHour, + i_pClient->m_sLog.dwMinutes, + i_pClient->m_sLog.dwSeconds, + i_pClient->m_sLog.dwMilliseconds, + i_pClient->m_sLog.dwMicroseconds, + i_pClient->m_sLog.dwNanoseconds + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatTimeMedium +void CClText::FormatTimeMedium(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%02d:%02d:%02d.%03d'%03d\"%d"), + i_pClient->m_sLog.dwHour, + i_pClient->m_sLog.dwMinutes, + i_pClient->m_sLog.dwSeconds, + i_pClient->m_sLog.dwMilliseconds, + i_pClient->m_sLog.dwMicroseconds, + i_pClient->m_sLog.dwNanoseconds + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatTimeShort +void CClText::FormatTimeShort(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%02d:%02d.%03d'%03d\"%d"), + i_pClient->m_sLog.dwMinutes, + i_pClient->m_sLog.dwSeconds, + i_pClient->m_sLog.dwMilliseconds, + i_pClient->m_sLog.dwMicroseconds, + i_pClient->m_sLog.dwNanoseconds + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatTimeDiff +void CClText::FormatTimeDiff(CClText *i_pClient) +{ + tUINT64 l_qwTime = i_pClient->m_sLog.qwRawTimeOffset; + tUINT64 l_dwReminder = l_qwTime % TIME_MSC_100NS; //micro & 100xNanoseconds + tUINT64 l_dwNano = l_qwTime % 10; + tUINT64 l_dwMicro = l_dwReminder / 10; + + l_qwTime -= l_dwReminder; + + tUINT64 l_qwSec = l_qwTime / TIME_SEC_100NS; + tUINT64 l_qwMSc = (l_qwTime - (l_qwSec * TIME_SEC_100NS)) / TIME_MSC_100NS; + + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("+%06d.%03d'%03d\"%d"), + (tUINT32)l_qwSec, + (tUINT32)l_qwMSc, + (tUINT32)l_dwMicro, + (tUINT32)l_dwNano + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatTimeCount +void CClText::FormatTimeCount(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%019lld"), + i_pClient->m_sLog.qwRawTime + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatLevel +void CClText::FormatLevel(CClText *i_pClient) +{ + if ( (i_pClient->m_sLog.eLevel >= EP7TRACE_LEVEL_COUNT) + || (i_pClient->m_sLog.eLevel < 0) + ) + { + i_pClient->m_sLog.eLevel = EP7TRACE_LEVEL_CRITICAL; + } + REALLOC_MESSAGE(LEVEL_TEXT_LENGTH + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, g_pLevel[i_pClient->m_sLog.eLevel], LEVEL_TEXT_LENGTH * sizeof(tXCHAR)); + i_pClient->m_pMsgCur += LEVEL_TEXT_LENGTH; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatThreadId +void CClText::FormatThreadId(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("0x%05X"), + i_pClient->m_sLog.dwThreadId + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatThreadName +void CClText::FormatThreadName(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.szThreadName + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, + i_pClient->m_sLog.pThreadName, + i_pClient->m_sLog.szThreadName * sizeof(tXCHAR) + ); + i_pClient->m_pMsgCur += i_pClient->m_sLog.szThreadName; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatCpuCore +void CClText::FormatCpuCore(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%02d"), + i_pClient->m_sLog.dwCpuCore + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatModuleId +void CClText::FormatModuleId(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%03d"), + i_pClient->m_sLog.dwModuleID + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatModuleName +void CClText::FormatModuleName(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.szModuleName + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, + i_pClient->m_sLog.pModuleName, + i_pClient->m_sLog.szModuleName * sizeof(tXCHAR) + ); + i_pClient->m_pMsgCur += i_pClient->m_sLog.szModuleName; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatFilePath +void CClText::FormatFilePath(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.pDesc->szFilePath + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, + i_pClient->m_sLog.pDesc->pFilePath, + i_pClient->m_sLog.pDesc->szFilePath * sizeof(tXCHAR) + ); + i_pClient->m_pMsgCur += i_pClient->m_sLog.pDesc->szFilePath; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatFileName +void CClText::FormatFileName(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.pDesc->szFileName + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, + i_pClient->m_sLog.pDesc->pFileName, + i_pClient->m_sLog.pDesc->szFileName * sizeof(tXCHAR) + ); + i_pClient->m_pMsgCur += i_pClient->m_sLog.pDesc->szFileName; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatFileLine +void CClText::FormatFileLine(CClText *i_pClient) +{ + REALLOC_MESSAGE(64, i_pClient); + + tINT32 l_iRes = PSPrint(i_pClient->m_pMsgCur, + i_pClient->m_szMsg - (i_pClient->m_pMsgCur - i_pClient->m_pMsg), + TM("%03d"), + (tUINT32)i_pClient->m_sLog.pDesc->wLine + ); + if (0 < l_iRes) + { + i_pClient->m_pMsgCur += l_iRes; + } +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatFunction +void CClText::FormatFunction(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.pDesc->szFunction + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, + i_pClient->m_sLog.pDesc->pFunction, + i_pClient->m_sLog.pDesc->szFunction * sizeof(tXCHAR) + ); + i_pClient->m_pMsgCur += i_pClient->m_sLog.pDesc->szFunction; +} + +//////////////////////////////////////////////////////////////////////////////// +//FormatMsg +void CClText::FormatMsg(CClText *i_pClient) +{ + REALLOC_MESSAGE(i_pClient->m_sLog.szMessage + 16, i_pClient); + memcpy(i_pClient->m_pMsgCur, + i_pClient->m_sLog.pMessage, + i_pClient->m_sLog.szMessage * sizeof(tXCHAR) + ); + i_pClient->m_pMsgCur += i_pClient->m_sLog.szMessage; +} + diff --git a/p7lib/Sources/ClText.h b/p7lib/Sources/ClText.h new file mode 100644 index 0000000..a29c03c --- /dev/null +++ b/p7lib/Sources/ClText.h @@ -0,0 +1,309 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to file / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLTEXT_H +#define CLTEXT_H + +#include "ClTextSink.h" +#include "ClTextConsole.h" +#include "ClTextFile.h" +#include "ClTextSyslog.h" +#include "Formatter.h" + +//////////////////////////////////////////////////////////////////////////////// +struct sTraceDescEx + : public sTraceDesc +{ + tUINT8 *pBuffer; + tUINT32 dwSize; + tXCHAR *pFormat; + sP7Trace_Arg *pArgs; + tUINT32 dwArgsLen; + CFormatter *pFormatter; + + sTraceDescEx(const sP7Trace_Format *i_pFormat, + CFormatter::sBuffer *i_pBuffer, + tBOOL i_bBigEndian); + ~sTraceDescEx(); +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sP7TraceMod +{ + eP7Trace_Level eVerbosity; + tXCHAR pName[P7TRACE_MODULE_NAME_LENGTH]; + size_t szName; +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sThread +{ + tUINT32 dwThreadID; //Thread ID + tUINT64 qwStart; //High resolution timer value start + tUINT64 qwStop; //High resolution timer value stop + tXCHAR pName[P7TRACE_THREAD_NAME_LENGTH]; //Thread name + size_t szName; +}; + + +//////////////////////////////////////////////////////////////////////////////// +struct sRbThread +{ + sThread *pThread; + sRbThread *pNext; + + sRbThread(sThread *i_pThread, sRbThread *i_pNext = NULL) + { + pThread = i_pThread; + pNext = i_pNext; + } + + ~sRbThread() + { + if (pThread) + { + delete pThread; + pThread = NULL; + } + + if (pNext) + { + delete pNext; + pNext = NULL; + } + } +}; + +//////////////////////////////////////////////////////////////////////////////// +class CThreads_Tree: + public CRBTree +{ +protected: + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(tUINT32 i_dwKey, sRbThread *i_pData) + { + return (i_dwKey < i_pData->pThread->dwThreadID) ? TRUE : FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(tUINT32 i_dwKey, sRbThread *i_pData) + { + return (i_dwKey == i_pData->pThread->dwThreadID) ? TRUE : FALSE; + } +}; + + + +//////////////////////////////////////////////////////////////////////////////// +class CTxtChannel +{ +protected: + //Contains a 64-bit value representing the number of 100-nanosecond intervals + //since January 1, 1601 (UTC). In windows we use FILETIME structure for + //representing + tUINT64 m_qwStreamTime; + //Hi resolution timer value, we get this value when we retrieve current time. + //using difference between this value and timer value for every trace we can + //calculate time of the trace event with hi resolution + tUINT64 m_qwTimer_Value; + //timer's count heartbeats in second + tUINT64 m_qwTimer_Frequency; + tUINT64 m_qwFlags; + + CBList m_cDesc; + CBList m_cModules; + CThreads_Tree m_cThreads; + tXCHAR *m_pText; + size_t m_szText; + tUINT64 m_qwTimeLast; + tXCHAR m_pName[P7TRACE_NAME_LENGTH]; + size_t m_szName; + CFormatter::sBuffer *m_pBuffer; + tBOOL m_bBig_Endian; + + //Time conversion for Linux + //http://stackoverflow.com/questions/2408976/struct-timeval-to-printable-format +public: + CTxtChannel(const sP7Trace_Info *i_pInfo, tBOOL i_bBig_Endian); + ~CTxtChannel(); + void PutFormat(const sP7Trace_Format *i_pDesc); + void PutModule(const sP7Trace_Module *i_pMod); + void RegisterThread(const sP7Trace_Thread_Start *i_pStart); + void UnregisterThread(const sP7Trace_Thread_Stop *i_pStop); + tBOOL Format(sP7Trace_Data* i_pData, CClTextSink::sLog &o_rLog); +}; + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// CClText +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +class CClText: + public CClient +{ +public: + typedef void (*fnFormat)(CClText *i_pClient); + +protected: + struct sFormat + { + tXCHAR *pStr; + size_t szStr; + fnFormat pFormat; + sFormat *pNext; + }; + + struct sBuffer + { + tUINT8 *pBuffer; + size_t szUsed; + + sBuffer(size_t i_szBuffer) + { + pBuffer = (tUINT8*)malloc(i_szBuffer); + szUsed = 0; + } + + ~sBuffer() + { + if (pBuffer) + { + free(pBuffer); + pBuffer = NULL; + } + szUsed = 0; + } + }; + +private: + tINT32 volatile m_lReject_Mem; + tINT32 volatile m_lReject_Con; + tINT32 volatile m_lReject_Int; + + CMEvent m_cEvThread; + tBOOL m_bThread; + CThShell::tTHREAD m_hThread; + CMEvent m_cEvData; + volatile tBOOL m_bNoData; + + CBList m_cBuffer_Empty; + CBList m_cBuffer_Ready; + sBuffer *m_pBuffer_Current; + tUINT32 m_dwBuffer_Size; + tUINT32 m_dwBuffers_Count; + + tBOOL m_bBig_Endian; + + tUINT8 *m_pChunk; + size_t m_szChunkMax; + size_t m_szChunkUsd; + CTxtChannel *m_pTxtCh[USER_PACKET_CHANNEL_ID_MAX_SIZE]; + CClTextSink::sLog m_sLog; + sFormat *m_pFormat; + tXCHAR *m_pMsg; + tXCHAR *m_pMsgCur; + size_t m_szMsg; + CClTextSink *m_pSink; + tBOOL m_bSinkExternal; + +public: + CClText(tXCHAR **i_pArgs, tINT32 i_iCount); + virtual ~CClText(); + +private: + eClient_Status Init_Base(tXCHAR **i_pArgs, tINT32 i_iCount); + + eClient_Status Init_Pool(tXCHAR **i_pArgs, tINT32 i_iCount); + + eClient_Status Init_Backend(tXCHAR **i_pArgs, tINT32 i_iCount); + + eClient_Status Init_Thread(tXCHAR **i_pArgs, tINT32 i_iCount); + + eClient_Status ParseFormat(const tXCHAR *i_pFormat); + + sFormat *AddFormatNode(const tXCHAR *i_pPrefix, + size_t i_szPrefix, + fnFormat i_pFn); + + +public: + eClient_Status Sent(tUINT32 i_dwChannel_ID, + sP7C_Data_Chunk *i_pChunks, + tUINT32 i_dwCount, + tUINT32 i_dwSize + ); + + tBOOL Get_Info(sP7C_Info *o_pInfo); + tBOOL Close(); + void Flush(); + +private: + eClient_Status Parse_Buffer(tUINT8 *i_pBuffer, size_t i_szBuffer); + eClient_Status Parse_Packet(tUINT32 i_dwChannel, tUINT8 *i_pPacket, size_t i_szPacket); + + static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_Routine(void *i_pContext) + { + CClText *l_pRoutine = static_cast(i_pContext); + if (l_pRoutine) + { + l_pRoutine->Routine(); + } + + CThShell::Cleanup(); + return THSHELL_RET_OK; + } + + void Routine(); + +public: + static void FormatChannel(CClText *i_pClient); + static void FormatMessageId(CClText *i_pClient); + static void FormatMessageIndex(CClText *i_pClient); + static void FormatTimeFull(CClText *i_pClient); + static void FormatTimeMedium(CClText *i_pClient); + static void FormatTimeShort(CClText *i_pClient); + static void FormatTimeDiff(CClText *i_pClient); + static void FormatTimeCount(CClText *i_pClient); + static void FormatLevel(CClText *i_pClient); + static void FormatThreadId(CClText *i_pClient); + static void FormatThreadName(CClText *i_pClient); + static void FormatCpuCore(CClText *i_pClient); + static void FormatModuleId(CClText *i_pClient); + static void FormatModuleName(CClText *i_pClient); + static void FormatFilePath(CClText *i_pClient); + static void FormatFileName(CClText *i_pClient); + static void FormatFileLine(CClText *i_pClient); + static void FormatFunction(CClText *i_pClient); + static void FormatMsg(CClText *i_pClient); +}; + + +#endif //CLTEXT_H diff --git a/p7lib/Sources/ClTextConsole.h b/p7lib/Sources/ClTextConsole.h new file mode 100644 index 0000000..5ee5a59 --- /dev/null +++ b/p7lib/Sources/ClTextConsole.h @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide printing to console / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLTEXTCONSOLE_H +#define CLTEXTCONSOLE_H + +//////////////////////////////////////////////////////////////////////////////// +class CClTextConsole + : public CClTextSink +{ +public: + CClTextConsole() + { + + } + virtual ~CClTextConsole() + { + + } + + virtual eClient_Status Initialize(tXCHAR **i_pArgs, tINT32 i_iCount) + { + UNUSED_ARG(i_pArgs); + UNUSED_ARG(i_iCount); + return ECLIENT_STATUS_OK; + } + + virtual eClient_Status Log(const CClTextSink::sLog &i_rRawLog, + const tXCHAR *i_pFmtLog, + size_t i_szFmtLog + ) + { + UNUSED_ARG(i_rRawLog); + UNUSED_ARG(i_szFmtLog); + #ifdef UTF8_ENCODING + printf("%s", i_pFmtLog); + #else + wprintf(L"%s", i_pFmtLog); + #endif + printf("\n"); + return ECLIENT_STATUS_OK; + } + + virtual eClient_Status DumpBuffers() { return ECLIENT_STATUS_OK; } +}; + + +#endif //CLTEXTCONSOLE_H diff --git a/p7lib/Sources/ClTextFile.h b/p7lib/Sources/ClTextFile.h new file mode 100644 index 0000000..b6390f1 --- /dev/null +++ b/p7lib/Sources/ClTextFile.h @@ -0,0 +1,634 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide printing to text file / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLTEXTFILE_H +#define CLTEXTFILE_H + +#include "IFile.h" +#include "PFile.h" + +#define TXT_FILE_DEF_FILES_COUNT 0 +#define TXT_FILE_EXT TM("txt") +#define TXT_FILE_WRITE_PERIOD 1000u + +//////////////////////////////////////////////////////////////////////////////// +class CClTextFile + : public CClTextSink +{ + enum eRolling + { + EROLLING_NONE, + EROLLING_MEGABYTES, + EROLLING_HOURS, + EROLLING_TIME, + + EROLLING_MAX + }; + + CPFile m_cFile; + CWString m_pDir; + eRolling m_eRolling; + tUINT64 m_qwRolling_Value; + tUINT32 m_dwFile_Tick; + tUINT32 m_dwWrite_Tick; + tUINT64 m_qwFile_Size; + tUINT32 m_dwFiles_Max_Count; + tUINT64 m_qwFiles_Max_Size; + CBList m_cFiles; + tXCHAR *m_pBuffer; + size_t m_szBuffer; + size_t m_szBufferOffs; + CUintList m_cSecondsList; + tUINT32 m_uiSecond; + tUINT32 m_dwIndex; + + +public: + //////////////////////////////////////////////////////////////////////////// + //CClTextFile + CClTextFile() + : m_eRolling(EROLLING_NONE) + , m_qwRolling_Value(0ull) + , m_dwFile_Tick(0u) + , m_dwWrite_Tick(0ull) + , m_qwFile_Size(0ull) + , m_dwFiles_Max_Count(0u) + , m_qwFiles_Max_Size(0u) + , m_pBuffer(NULL) + , m_szBuffer(0x10000) + , m_szBufferOffs(0) + , m_dwIndex(0) + { + m_dwWrite_Tick = GetTickCount(); + m_uiSecond = GetSecondOfDay(); + } + + //////////////////////////////////////////////////////////////////////////// + //~CClTextFile + virtual ~CClTextFile() + { + m_cFile.Write((tUINT8*)m_pBuffer, m_szBufferOffs * sizeof(tXCHAR), FALSE); + m_cFile.Close(TRUE); + + m_cFiles.Clear(TRUE); + if (m_pBuffer) + { + free(m_pBuffer); + m_pBuffer = NULL; + } + m_szBufferOffs = 0; + + m_cSecondsList.Clear(TRUE); + } + + //////////////////////////////////////////////////////////////////////////// + //Initialize + virtual eClient_Status Initialize(tXCHAR **i_pArgs, tINT32 i_iCount) + { + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tXCHAR *l_pArgV = NULL; + pAList_Cell l_pStart = NULL; + tUINT32 l_dwDirLen = 0; + + m_pDir.Realloc(4096); + + m_pBuffer = (tXCHAR*)malloc(m_szBuffer * sizeof(tXCHAR)); + if (!m_pBuffer) + { + PRINTF(TM("P7:Can't allocate memory\n")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + goto l_lblExit; + } + + //unicode marker + #ifdef UTF8_ENCODING + m_pBuffer[0] = (char)0xEF; + m_pBuffer[1] = (char)0xBB; + m_pBuffer[2] = (char)0xBF; + m_szBufferOffs = 3; + m_qwFile_Size = 3; + #else + m_pBuffer[0] = 0xFEFF; + m_szBufferOffs = 1; + m_qwFile_Size = sizeof(tXCHAR); + #endif + + //////////////////////////////////////////////////////////////////////////// + //get maximum count of the log files + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_FILES_COUNT_MAX + ); + if (l_pArgV) + { + m_dwFiles_Max_Count = (tUINT32)PStrToInt(l_pArgV); + + if (4096 < m_dwFiles_Max_Count) + { + m_dwFiles_Max_Count = TXT_FILE_DEF_FILES_COUNT; + } + } + + + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_FILES_SIZE_MAX + ); + if (l_pArgV) + { + m_qwFiles_Max_Size = (tUINT64)PStrToInt(l_pArgV) * 1048576ull; + } + + + //////////////////////////////////////////////////////////////////////////// + //get path to storage + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_DIR + ); + if (l_pArgV) + { + m_pDir.Set(l_pArgV); + } + else + { + CProc::Get_Process_Path(m_pDir.Get(), m_pDir.Max_Length()); + m_pDir.Append(1, TM("/P7logs/")); + } + + if (FALSE == CFSYS::Directory_Exists(m_pDir.Get())) + { + if (FALSE == CFSYS::Directory_Create(m_pDir.Get())) + { + P7_Set_Last_Error(eP7_Error_FolderCreation); + PRINTF(TM("P7:Can't create directory: %s\n"), l_pArgV); + l_eReturn = ECLIENT_STATUS_NOT_ALLOWED; + goto l_lblExit; + } + } + + //////////////////////////////////////////////////////////////////////////// + //enumerate files & sorting .... + if ( (TXT_FILE_DEF_FILES_COUNT != m_dwFiles_Max_Count) + || (m_qwFiles_Max_Size) + ) + { + CFSYS::Enumerate_Files(&m_cFiles, &m_pDir, TM("*.") TXT_FILE_EXT, 0); + + l_pStart = NULL; + l_dwDirLen = m_pDir.Length(); + + while ((l_pStart = m_cFiles.Get_Next(l_pStart))) + { + pAList_Cell l_pMin = l_pStart; + pAList_Cell l_pIter = l_pStart; + + while ((l_pIter = m_cFiles.Get_Next(l_pIter))) + { + CWString *l_pPathM = m_cFiles.Get_Data(l_pMin); + CWString *l_pPathI = m_cFiles.Get_Data(l_pIter); + tXCHAR *l_pNameM = l_pPathM->Get() + l_dwDirLen; + tXCHAR *l_pNameI = l_pPathI->Get() + l_dwDirLen; + + if (0 < PStrICmp(l_pNameM, l_pNameI)) + { + l_pMin = l_pIter; + } + } + + if (l_pMin != l_pStart) + { + m_cFiles.Extract(l_pMin); + m_cFiles.Put_After(m_cFiles.Get_Prev(l_pStart), l_pMin); + l_pStart = l_pMin; + } + } //while (l_pStart = m_cFiles.Get_Next(l_pStart)) + } + + //////////////////////////////////////////////////////////////////////////// + //create file + l_eReturn = Create_File(); + if (ECLIENT_STATUS_OK != l_eReturn) + { + P7_Set_Last_Error(eP7_Error_FileCreation); + PRINTF(TM("P7:File creation failed")); + goto l_lblExit; + } + + + //////////////////////////////////////////////////////////////////////////// + //get rolling type + l_pArgV = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_FILE_ROLLING + ); + if (l_pArgV) + { + CWString l_cRolling(l_pArgV); + tUINT32 l_dwLen = l_cRolling.Length(); + tBOOL l_bError = FALSE; + + if (3 <= l_dwLen) + { + tXCHAR *l_pSuffix = l_cRolling.Get() + l_dwLen - 2; + if (0 == PStrICmp(l_pSuffix, TM("hr"))) + { + m_eRolling = EROLLING_HOURS; + } + else if (0 == PStrICmp(l_pSuffix, TM("mb"))) + { + m_eRolling = EROLLING_MEGABYTES; + } + else if (0 == PStrICmp(l_pSuffix, TM("tm"))) + { + m_eRolling = EROLLING_TIME; + } + else + { + l_bError = TRUE; + } + + //cut off suffix + l_cRolling.Trim(l_dwLen - 2); + } + else + { + l_bError = TRUE; + } + + if (FALSE == l_bError) + { + if (m_eRolling != EROLLING_TIME) + { + m_qwRolling_Value = PStrToInt(l_cRolling.Get()); + + if (0 >= m_qwRolling_Value) + { + m_eRolling = EROLLING_NONE; + l_bError = TRUE; + } + } + else + { + if (!Parse_Rolling_Time(l_cRolling.Get())) + { + m_eRolling = EROLLING_NONE; + l_bError = TRUE; + } + } + } + + if (l_bError) + { + PRINTF(TM("P7:Rolling value is not correct = %s\n"), l_cRolling.Get()); + } + + if (EROLLING_MEGABYTES == m_eRolling) + { + m_qwRolling_Value *= 0x100000ULL; //megabytes + } + else if (EROLLING_HOURS == m_eRolling) + { + if (m_qwRolling_Value > 1000) + { + PRINTF(TM("P7:Rolling value is more than 1000 hours, cutting\n")); + m_qwRolling_Value = 1000; + } + + m_qwRolling_Value *= 3600000ULL; //milliseconds in one hour + } + }//if (l_pArgV) + + l_lblExit: + return l_eReturn; + } + + + //////////////////////////////////////////////////////////////////////////////// + //Parse_Rolling_Time + tBOOL Parse_Rolling_Time(const tXCHAR *i_pTime) + { + const tXCHAR *l_pIter = i_pTime; + const tXCHAR *l_pBegin = i_pTime; + tBOOL l_bReturn = TRUE; + + while (*l_pIter) + { + tUINT32 l_uiSeconds = 0; + tUINT32 l_uiValue = 0; + + l_pBegin = l_pIter; //scan hours + while ( (*l_pIter >= TM('0')) + && (*l_pIter <= TM('9')) + ) + { + l_uiValue = l_uiValue * 10 + (*l_pIter - TM('0')); + l_pIter ++; + } + + if (l_pBegin == l_pIter) //no digits + { + l_bReturn = FALSE; + break; + } + + l_uiSeconds = l_uiValue * 3600; + + if (*l_pIter != TM(':')) //error + { + l_bReturn = FALSE; + break; + } + + l_pIter++; + + l_pBegin = l_pIter; //scan minutes + l_uiValue = 0; + while ( (*l_pIter >= TM('0')) + && (*l_pIter <= TM('9')) + ) + { + l_uiValue = l_uiValue * 10 + (*l_pIter - TM('0')); + l_pIter ++; + } + + if (l_pBegin == l_pIter) //no digits + { + l_bReturn = FALSE; + break; + } + + l_uiSeconds += l_uiValue * 60; + + m_cSecondsList.Add_After(m_cSecondsList.Get_Last(), l_uiSeconds); + + if (*l_pIter == TM(',')) + { + l_pIter++; + } + } + + if (!m_cSecondsList.Count()) + { + l_bReturn = FALSE; + } + + return l_bReturn; + }//Parse_Rolling_Time + + + //////////////////////////////////////////////////////////////////////////// + //Log + virtual eClient_Status Log(const CClTextSink::sLog &i_rRawLog, + const tXCHAR *i_pFmtLog, + size_t i_szFmtLog + ) + { + UNUSED_ARG(i_rRawLog); + if ( ((i_szFmtLog + 16) > (m_szBuffer - m_szBufferOffs)) + || (CTicks::Difference(GetTickCount(), m_dwWrite_Tick) >= TXT_FILE_WRITE_PERIOD) + ) + { + if ((i_szFmtLog + 16) > m_szBuffer) + { + if (m_szBufferOffs) + { + m_cFile.Write((tUINT8*)m_pBuffer, m_szBufferOffs * sizeof(tXCHAR), FALSE); + m_szBufferOffs = 0u; + } + + m_cFile.Write((tUINT8*)i_pFmtLog, i_szFmtLog * sizeof(tXCHAR), FALSE); + m_qwFile_Size += (i_szFmtLog + 2) * sizeof(tXCHAR); + *(m_pBuffer) = TM('\r'); + *(m_pBuffer + 1) = TM('\n'); + m_szBufferOffs += 2; + + TryRoll(); + + return ECLIENT_STATUS_OK; + } + else + { + m_cFile.Write((tUINT8*)m_pBuffer, m_szBufferOffs * sizeof(tXCHAR), FALSE); + m_szBufferOffs = 0; + + TryRoll(); + } + + m_dwWrite_Tick = GetTickCount(); + } + + memcpy(m_pBuffer + m_szBufferOffs, i_pFmtLog, sizeof(tXCHAR) * i_szFmtLog); + m_szBufferOffs += i_szFmtLog; + *(m_pBuffer + m_szBufferOffs) = TM('\r'); + *(m_pBuffer + m_szBufferOffs + 1) = TM('\n'); + m_szBufferOffs += 2; + m_qwFile_Size += (i_szFmtLog + 2) * sizeof(tXCHAR); + + return ECLIENT_STATUS_OK; + } + + //////////////////////////////////////////////////////////////////////////// + // TryRoll + eClient_Status TryRoll() + { + if ( ( (EROLLING_HOURS == m_eRolling) + && (CTicks::Difference(GetTickCount(), m_dwFile_Tick) > m_qwRolling_Value) + ) + || ( (EROLLING_MEGABYTES == m_eRolling) + && (m_qwRolling_Value <= m_qwFile_Size) + ) + ) + { + Roll(); + } + else if (EROLLING_TIME == m_eRolling) + { + tUINT32 l_uiNextSecond = GetSecondOfDay(); + pAList_Cell l_pEl = NULL; + + while ((l_pEl = m_cSecondsList.Get_Next(l_pEl))) + { + tUINT32 l_uiIem = m_cSecondsList.Get_Data(l_pEl); + if ( (m_uiSecond <= l_uiIem) + && (l_uiNextSecond > l_uiIem) + ) + { + Roll(); + break; + } + } + + m_uiSecond = l_uiNextSecond; + } + + return ECLIENT_STATUS_OK; + }// TryRoll + + + //////////////////////////////////////////////////////////////////////////// + // Roll + void Roll() + { + m_cFile.Write((tUINT8*)m_pBuffer, m_szBufferOffs * sizeof(tXCHAR), TRUE); + m_cFile.Close(TRUE); + m_qwFile_Size = 0ull; + m_szBufferOffs = 0u; + Create_File(); + m_dwWrite_Tick = GetTickCount(); + }// Roll + + //////////////////////////////////////////////////////////////////////////// + // Create_File + eClient_Status Create_File() + { + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + tUINT32 l_dwYear = 0; + tUINT32 l_dwMonth = 0; + tUINT32 l_dwDay = 0; + tUINT32 l_dwHr = 0; + tUINT32 l_dwMin = 0; + tUINT32 l_dwSec = 0; + tUINT32 l_dwmSec = 0; + CWString l_cFilePath; + tXCHAR l_pFile_Name[64]; + + m_cFile.Close(TRUE); + + CSys::Get_DateTime(l_dwYear, + l_dwMonth, + l_dwDay, + l_dwHr, + l_dwMin, + l_dwSec, + l_dwmSec + ); + l_dwmSec = 0; + do + { + PSPrint(l_pFile_Name, + LENGTH(l_pFile_Name), + TM("/%04d%02d%02d-%02d%02d%02d%03d.") TXT_FILE_EXT, + l_dwYear, + l_dwMonth, + l_dwDay, + l_dwHr, + l_dwMin, + l_dwSec, + m_dwIndex + ); + + l_cFilePath.Set(m_pDir.Get()); + l_cFilePath.Append(1, l_pFile_Name); + + m_dwIndex ++; + } while (TRUE == CFSYS::File_Exists(l_cFilePath.Get())); + + if (FALSE == m_cFile.Open(l_cFilePath.Get(), + IFile::ECREATE | IFile::EACCESS_WRITE | IFile::ESHARE_READ + ) + ) + { + PRINTF(TM("P7:Can't create file: %s"), l_cFilePath.Get()); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + else + { + m_cFiles.Add_After(m_cFiles.Get_Last(), new CWString(l_cFilePath.Get())); + + if (TXT_FILE_DEF_FILES_COUNT != m_dwFiles_Max_Count) + { + while (m_dwFiles_Max_Count < m_cFiles.Count()) + { + pAList_Cell l_pEl = m_cFiles.Get_First(); + CWString *l_pPath = m_cFiles.Get_Data(l_pEl); + if (l_pPath) + { + if (!CFSYS::Delete_File(l_pPath->Get())) + { + PRINTF(TM("P7:Can't delete file: %s"), l_pPath->Get()); + } + } + + m_cFiles.Del(l_pEl, TRUE); + } + } + + if (0 != m_qwFiles_Max_Size) + { + pAList_Cell l_pEl = NULL; + tUINT64 l_qwTotalSize = 0; + tUINT64 l_qwFileSize = 0; + + while ((l_pEl = m_cFiles.Get_Next(l_pEl))) + { + CWString *l_pPath = m_cFiles.Get_Data(l_pEl); + if (l_pPath) + { + l_qwTotalSize += CFSYS::Get_File_Size(l_pPath->Get()); + } + } + + while (l_qwTotalSize > (m_qwFiles_Max_Size)) + { + pAList_Cell l_pEl = m_cFiles.Get_First(); + CWString *l_pPath = m_cFiles.Get_Data(l_pEl); + if (l_pPath) + { + l_qwFileSize = CFSYS::Get_File_Size(l_pPath->Get()); + + if (l_qwFileSize < l_qwTotalSize) + { + l_qwTotalSize -= l_qwFileSize; + } + else + { + l_qwTotalSize = 0ull; + } + + if (!CFSYS::Delete_File(l_pPath->Get())) + { + PRINTF(TM("Can't delete file: %s"), l_pPath->Get()); + } + } + + m_cFiles.Del(l_pEl, TRUE); + } + } + } + + m_dwFile_Tick = GetTickCount(); + + return l_eReturn; + }// Create_File + + virtual eClient_Status DumpBuffers() + { + if (m_szBufferOffs) + { + m_cFile.Write((tUINT8*)m_pBuffer, m_szBufferOffs * sizeof(tXCHAR), TRUE); + m_szBufferOffs = 0; + } + + return ECLIENT_STATUS_OK; + } + +}; + +#endif //CLTEXTFILE_H diff --git a/p7lib/Sources/ClTextSink.h b/p7lib/Sources/ClTextSink.h new file mode 100644 index 0000000..d0bd216 --- /dev/null +++ b/p7lib/Sources/ClTextSink.h @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file describes interface for text sink / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLTEXTSINK_H +#define CLTEXTSINK_H + + +//////////////////////////////////////////////////////////////////////////////// +struct sTraceDesc +{ + tUINT16 wLine; + tXCHAR *pFilePath; + size_t szFilePath; + const tXCHAR *pFileName; //pointer to pFile_Path + size_t szFileName; + tXCHAR *pFunction; + size_t szFunction; + tUINT32 dwModuleID; //module ID when trace description was created + + sTraceDesc() + : wLine(0) + , pFilePath(NULL) + , szFilePath(0) + , pFileName(NULL) + , szFileName(0) + , pFunction(NULL) + , szFunction(0) + , dwModuleID(0) + { + } +}; + + +//////////////////////////////////////////////////////////////////////////////// +class CClTextSink +{ +public: + struct sLog + { + const tXCHAR *pChannel; //channel name + size_t szChannel; //channel name length + tUINT64 qwIndex; //log item index (per channel) + tUINT32 dwId; //log item ID (per channel) + tUINT32 dwYear; //year + tUINT32 dwMonth; //month + tUINT32 dwDay; //day + tUINT32 dwHour; //hour + tUINT32 dwMinutes; //minute + tUINT32 dwSeconds; //seconds + tUINT32 dwMilliseconds; //milliseconds + tUINT32 dwMicroseconds; //microseconds + tUINT32 dwNanoseconds; //nanoseconds + tUINT64 qwRawTime; //number of 100-nanosecond intervals since 01.01.1601 (UTC) + tUINT64 qwRawTimeOffset; //offset of 100-nanosecond intervals since prev. item + eP7Trace_Level eLevel; //log item level + tUINT32 dwModuleID; //module ID for current trace item + const tXCHAR *pModuleName; //module name + size_t szModuleName; //module name length + tUINT32 dwCpuCore; //current CPU core number + tUINT32 dwThreadId; //thread ID + const tXCHAR *pThreadName; //thread name + size_t szThreadName; //thread name length + sTraceDesc *pDesc; //log item description + const tXCHAR *pMessage; //log item message + size_t szMessage; //log item message length + }; + + CClTextSink() {} + virtual ~CClTextSink() {} + + virtual eClient_Status Initialize(tXCHAR **i_pArgs, tINT32 i_iCount) = 0; + virtual eClient_Status Log(const CClTextSink::sLog &i_rRawLog, + const tXCHAR *i_pFmtLog, + size_t i_szFmtLog + ) = 0; + + virtual eClient_Status TryRoll() { return ECLIENT_STATUS_OK; } + virtual eClient_Status DumpBuffers() = 0; +}; + + +#endif //CLTEXTSINK_H diff --git a/p7lib/Sources/ClTextSyslog.h b/p7lib/Sources/ClTextSyslog.h new file mode 100644 index 0000000..9b87d92 --- /dev/null +++ b/p7lib/Sources/ClTextSyslog.h @@ -0,0 +1,301 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide printing to console / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CLTEXTSYSLOG_H +#define CLTEXTSYSLOG_H + +#define TXT_SYSLOG_DEFAULT_PORT TM("514") + +//RFC: +//https://tools.ietf.org/html/rfc5424 + +//////////////////////////////////////////////////////////////////////////////// +class CClTextSyslog + : public CClTextSink +{ +protected: + tBOOL m_bIsWinsock; + CUDP_Socket *m_pSocket; + tUINT32 m_pSeverity[EP7TRACE_LEVEL_COUNT]; + tUINT32 m_dwFacility; + tACHAR m_pHostName[96]; + tACHAR m_pProcName[96]; + //minimal size of UDP packet is 576 bytes minus header and extra = 512 + //to drive the size of the buffer please use CLIENT_COMMAND_PACKET_BAICAL_SIZE + //parameter, for example /P7.PSize=1478 + //Message size RFC: https://tools.ietf.org/html/rfc5426#page-3 + tACHAR *m_pBuffer; + size_t m_szBuffer; + tUINT32 m_dwProcId; + +public: + //////////////////////////////////////////////////////////////////////////// + //CClTextSyslog + CClTextSyslog() + : m_bIsWinsock(FALSE) + , m_pSocket(NULL) + , m_dwFacility(1) + , m_pBuffer(0) + , m_szBuffer(1472) + , m_dwProcId(0) + { + CSys::Get_Host_Name(m_pHostName, LENGTH(m_pHostName)); + CProc::Get_Process_Name(m_pProcName, LENGTH(m_pProcName)); + m_dwProcId = CProc::Get_Process_ID(); + + tACHAR *l_pIter = m_pHostName; + while (*l_pIter) + { + if (' ' == (*l_pIter)) + { + *l_pIter = '_'; + } + l_pIter++; + } + + l_pIter = m_pProcName; + while (*l_pIter) + { + if (' ' == (*l_pIter)) + { + *l_pIter = '_'; + } + l_pIter++; + } + + //Mapping P7 levels to syslog severity + //https://tools.ietf.org/html/rfc3164#page-8 + m_pSeverity[EP7TRACE_LEVEL_TRACE] = 7; //Debug: debug-level messages + m_pSeverity[EP7TRACE_LEVEL_DEBUG] = 7; //Debug: debug-level messages + m_pSeverity[EP7TRACE_LEVEL_INFO] = 6; //Informational: informational messages + m_pSeverity[EP7TRACE_LEVEL_WARNING] = 4; //Warning: warning conditions + m_pSeverity[EP7TRACE_LEVEL_ERROR] = 3; //Error: error conditions + m_pSeverity[EP7TRACE_LEVEL_CRITICAL] = 2; //Critical: critical conditions + }//CClTextSyslog + + //////////////////////////////////////////////////////////////////////////// + //~CClTextSyslog + virtual ~CClTextSyslog() + { + if (m_bIsWinsock) + { + WSA_UnInit(); + m_bIsWinsock = FALSE; + } + + if (m_pSocket) + { + delete m_pSocket; + m_pSocket = NULL; + } + + if (m_pBuffer) + { + free(m_pBuffer); + m_pBuffer = NULL; + } + }//~CClTextSyslog + + //////////////////////////////////////////////////////////////////////////// + //Initialize + virtual eClient_Status Initialize(tXCHAR **i_pArgs, tINT32 i_iCount) + { + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + + if (FALSE == WSA_Init()) + { + P7_Set_Last_Error(eP7_Error_Network); + PRINTF(TM("Windows Socket initialization fails!")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + else + { + m_bIsWinsock = TRUE; + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + tXCHAR *l_pAddr = NULL; + tXCHAR *l_pPort = NULL; + tADDR_INFO *l_pInfo = NULL; + tADDR_INFO *l_pNext = NULL; + tADDR_INFO l_tHint; + + memset(&l_tHint, 0, sizeof(l_tHint)); + + l_pAddr = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_ADDRESS); + if (NULL == l_pAddr) + { + l_pAddr = (tXCHAR*)TM("127.0.0.1"); + } + + l_pPort = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_LINE_BAICAL_PORT); + + if (NULL == l_pPort) + { + l_pPort = (tXCHAR*)TXT_SYSLOG_DEFAULT_PORT; + } + + l_tHint.ai_family = AF_UNSPEC; //AF_INET; + l_tHint.ai_socktype = SOCK_DGRAM; + l_tHint.ai_protocol = IPPROTO_UDP; + + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + + //http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520(v=vs.85).aspx + //http://linux.die.net/man/3/getaddrinfo + if (0 == GET_ADDR_INFO(l_pAddr, l_pPort, &l_tHint, &l_pInfo)) + { + for(l_pNext = l_pInfo; l_pNext != NULL ;l_pNext=l_pNext->ai_next) + { + if ( ( (AF_INET == l_pNext->ai_family) + || (AF_INET6 == l_pNext->ai_family) + ) + && (SOCK_DGRAM == l_pNext->ai_socktype) + && (IPPROTO_UDP == l_pNext->ai_protocol) + ) + { + m_pSocket = new CUDP_Socket(NULL, + (sockaddr*) l_pNext->ai_addr, + FALSE); + if (m_pSocket) + { + if (m_pSocket->Initialized()) + { + l_eReturn = ECLIENT_STATUS_OK; + break; + } + else + { + delete m_pSocket; + m_pSocket = NULL; + } + } + } + } + } //if (0 == GetAddrInfoW + + if (l_pInfo) + { + FREE_ADDR_INFO(l_pInfo); + l_pInfo = NULL; + } + } + + if (ECLIENT_STATUS_OK == l_eReturn) + { + tXCHAR *l_pValue = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_SYSLOG_FACILITY); + if (l_pValue) + { + m_dwFacility = (tUINT32)PStrToInt(l_pValue); + } + + l_pValue = Get_Argument_Text_Value(i_pArgs, i_iCount, + (tXCHAR*)CLIENT_COMMAND_PACKET_BAICAL_SIZE); + if (l_pValue) + { + m_szBuffer = (tUINT32)PStrToInt(l_pValue); + } + + if (512 > m_szBuffer) + { + m_szBuffer = 512; + } + + if (m_szBuffer > 65512) + { + m_szBuffer = 65512; + } + + m_pBuffer = (tACHAR*)malloc(m_szBuffer); + if (!m_pBuffer) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + PRINTF(TM("Memory allocation fails!")); + l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + } + } + else + { + P7_Set_Last_Error(eP7_Error_Network); + } + + return l_eReturn; + }//Initialize + + //////////////////////////////////////////////////////////////////////////// + //Log + virtual eClient_Status Log(const CClTextSink::sLog &i_rRawLog, + const tXCHAR *i_pFmtLog, + size_t i_szFmtLog + ) + { + tINT32 l_iLen = PSPrint(m_pBuffer, + m_szBuffer, + "<%d>1 %04d-%02d-%02dT%02d:%02d:%02d.%03dZ %s %s %d - - ", + m_dwFacility * 8 + m_pSeverity[i_rRawLog.eLevel], + i_rRawLog.dwYear, + i_rRawLog.dwMonth, + i_rRawLog.dwDay, + i_rRawLog.dwHour, + i_rRawLog.dwMinutes, + i_rRawLog.dwSeconds, + i_rRawLog.dwMilliseconds, + m_pHostName, + m_pProcName, + m_dwProcId + ); + if (0 < l_iLen) + { + #ifdef UTF8_ENCODING + if ((m_szBuffer - l_iLen) <= i_szFmtLog) + { + i_szFmtLog = m_szBuffer - l_iLen - 1; //overflow isn't possible + } + + memcpy(m_pBuffer + l_iLen, i_pFmtLog, i_szFmtLog); + l_iLen += (tINT32)i_szFmtLog; + m_pBuffer[l_iLen] = 0; + #else + tINT32 l_iTmp = Convert_UTF16_To_UTF8(i_pFmtLog, + m_pBuffer + l_iLen, + (tUINT32)(m_szBuffer - l_iLen) + ); + if (0 < l_iTmp) + { + l_iLen += l_iTmp; + } + #endif + + m_pSocket->Send(m_pBuffer, l_iLen + 1); + } + + return ECLIENT_STATUS_OK; + }//Log + + virtual eClient_Status DumpBuffers() { return ECLIENT_STATUS_OK; } +}; + +#endif //CLTEXTSYSLOG_H diff --git a/p7lib/Sources/Client.cpp b/p7lib/Sources/Client.cpp new file mode 100644 index 0000000..89a49d4 --- /dev/null +++ b/p7lib/Sources/Client.cpp @@ -0,0 +1,1231 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide client functionality / +//////////////////////////////////////////////////////////////////////////////// + +#include "CommonClient.h" +#include "PSignal.h" +#include "Client.h" +#include "ClBaical.h" +#include "ClFile.h" +#include "ClText.h" +#include "ClNull.h" + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Defines +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +#define CRASH_HANDLER_NAME TM("Crash") +#define CRASH_LOCK_TIMEOUT 300000 +#define CRASH_CLIENTS_COUNT (8) +#define CLIENT_SHARED_PREFIX TM("Cln_") + +struct sCrash +{ + tINT32 volatile lReference; + CShared::hShared hShared; + tUINT64 qwTimeStamp; + CClient *pClients[CRASH_CLIENTS_COUNT]; +}; + + +extern "C" +{ + +//////////////////////////////////////////////////////////////////////////////// +//P7_Create_Client +P7_EXPORT IP7_Client * __cdecl P7_Create_Client(const tXCHAR *i_pArgs) +{ + IP7_Client *l_pReturn = NULL; + int l_iHC_ArgsC = 0; + tXCHAR **l_pHC_Args = i_pArgs ? CProc::Get_ArgV(i_pArgs, &l_iHC_ArgsC) : NULL; + int l_iCn_ArgsC = 0; + tXCHAR **l_pCn_Args = CProc::Get_ArgV(&l_iCn_ArgsC); + int l_iCount = l_iCn_ArgsC + l_iHC_ArgsC; + tXCHAR **l_pArgs = NULL; + tXCHAR *l_pSink = NULL; + tXCHAR *l_pOn = NULL; + + //////////////////////////////////////////////////////////////////////////// + //Parse command line from console and from source code, + //priority belongs to console + if (l_iCount) + { + l_pArgs = (tXCHAR **)malloc(sizeof(tXCHAR *) * l_iCount); + if (l_pArgs) + { + for (int l_iI = 0; l_iI < l_iCn_ArgsC; l_iI ++) + { + l_pArgs[l_iI] = l_pCn_Args[l_iI]; + } + + for (int l_iI = l_iCn_ArgsC; l_iI < l_iCount; l_iI ++) + { + l_pArgs[l_iI] = l_pHC_Args[l_iI - l_iCn_ArgsC]; + } + } + else + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + } + } + + l_pSink = Get_Argument_Text_Value(l_pArgs, l_iCount, CLIENT_COMMAND_LINE_SINK); + l_pOn = Get_Argument_Text_Value(l_pArgs, l_iCount, CLIENT_COMMAND_LOG_ON); + + //////////////////////////////////////////////////////////////////////////// + //select proper Sink + if ( (NULL != l_pOn) + && (TM('0') == l_pOn[0]) + ) + { + //OFF + } + else if ( (NULL == l_pSink) + || (0 == PStrICmp(l_pSink, CLIENT_SINK_BAICAL)) + ) + { + l_pReturn = static_cast(new CClBaical(l_pArgs, l_iCount)); + } + else if ( (0 == PStrICmp(l_pSink, CLIENT_SINK_FILE_BIN)) + || (0 == PStrICmp(l_pSink, CLIENT_SINK_FILE_BIN_LEGACY)) + ) + { + l_pReturn = static_cast(new CClFile(l_pArgs, l_iCount)); + } + else if (0 == PStrICmp(l_pSink, CLIENT_SINK_AUTO)) + { + CClBaical *l_pBaical = new CClBaical(l_pArgs, l_iCount); + if ( (l_pBaical) + && ( (ECLIENT_STATUS_OK != l_pBaical->Get_Status()) + || (FALSE == l_pBaical->Connection_Wait(250)) + ) + ) + { + delete l_pBaical; + l_pBaical = NULL; + } + + if (l_pBaical) + { + l_pReturn = static_cast(l_pBaical); + } + else + { + l_pReturn = static_cast(new CClFile(l_pArgs, l_iCount)); + } + } + else if (0 == PStrICmp(l_pSink, CLIENT_SINK_NULL)) + { + l_pReturn = static_cast(new CClNull(l_pArgs, l_iCount)); + } + else //all other sink are text one + //(0 == PStrICmp(l_pSink, CLIENT_SINK_FILE_TXT)) + //(0 == PStrICmp(l_pSink, CLIENT_SINK_CONSOLE)) + //(0 == PStrICmp(l_pSink, CLIENT_SINK_SYSLOG)) + { + l_pReturn = static_cast(new CClText(l_pArgs, l_iCount)); + } + + //if not initialized - remove + if ( (l_pReturn) + && (ECLIENT_STATUS_OK != l_pReturn->Get_Status()) + ) + { + l_pReturn->Release(); + l_pReturn = NULL; + } + + + //////////////////////////////////////////////////////////////////////////// + //do we need to print help + if ( Get_Argument_Text_Value(l_pArgs, l_iCount, + (const tXCHAR*)CLIENT_COMMAND_LOG_HELP + ) + ) + { + PRINTF((tXCHAR*)CLIENT_HELP_STRING); + } + + + //////////////////////////////////////////////////////////////////////////// + //cleanup + if (l_pHC_Args) + { + CProc::Free_ArgV(l_pHC_Args); + l_pHC_Args = NULL; + } + + if (l_pCn_Args) + { + CProc::Free_ArgV(l_pCn_Args); + l_pCn_Args = NULL; + } + + if (l_pArgs) + { + free(l_pArgs); + l_pArgs = NULL; + } + + return l_pReturn; +}//P7_Create_Client + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Get_Shared +P7_EXPORT IP7_Client * __cdecl P7_Get_Shared(const tXCHAR *i_pName) +{ + IP7_Client *l_pReturn = NULL; + tUINT32 l_dwLen1 = PStrLen(CLIENT_SHARED_PREFIX); + tUINT32 l_dwLen2 = PStrLen(i_pName); + tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + sObjShared l_stShared = {}; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + + if (l_pName) + { + PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, CLIENT_SHARED_PREFIX); + PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); + + if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) + { + if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) + { + if ( (l_stShared.uProcTimeHi == l_uTimeHi) + && (l_stShared.uProcTimeLo == l_uTimeLo) + ) + { + l_pReturn = static_cast(l_stShared.pPointer); + if (l_pReturn) + { + l_pReturn->Add_Ref(); + } + } + else + { + P7_Set_Last_Error(eP7_Error_SharedObjectInvalid); + CShared::UnLink(l_pName); + } + } + + CShared::UnLock(l_hSem); + } + + free(l_pName); + l_pName = NULL; + } + else + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + } + + return l_pReturn; +}//P7_Get_Shared + + +//////////////////////////////////////////////////////////////////////////////// +//cbCrashHandler +void __cdecl cbCrashHandler(eCrashCode i_eCode, const void *i_pCrashContext, void *i_pUserContext) +{ + UNUSED_ARG(i_eCode); + UNUSED_ARG(i_pCrashContext); + UNUSED_ARG(i_pUserContext); + P7_Exceptional_Flush(); +}//cbCrashHandler + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Set_Crash_Handler +P7_EXPORT void __cdecl P7_Set_Crash_Handler() +{ + ChInstall(); + ChSetHandler(&cbCrashHandler); +}//P7_Set_Crash_Handler + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Clr_Crash_Handler +P7_EXPORT void __cdecl P7_Clr_Crash_Handler() +{ + ChUnInstall(); +}//P7_Clr_Crash_Handler + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Exceptional_Flush +//0) Lock crash memory +//1) Read crash memory +//2) Call every client crash functions +//3) - every client set "Error" flag to prevent ext. access (add data, add/del channel) +//4) - every client call crash function on every channel +//5) - some channels will dump stack back trace & exception info +//6) - every channel close connection & set "Error" flag +//7) - every client write/deliver all buffers +//8) - every client release shared memory +//9) unlock crash memory +//10) release crash memory +//11) leave function to execute def. handler +P7_EXPORT void __cdecl P7_Exceptional_Flush() +{ + tBOOL l_bLock = FALSE; + sCrash l_sCrash = {}; + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + tUINT64 l_qwProcTime = 0; + tBOOL l_bTimeError = FALSE; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + + if (CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo)) + { + l_qwProcTime = ((tUINT64)l_uTimeHi << 32) + (tUINT64)l_uTimeLo; + } + + //////////////////////////////////////////////////////////////////////////// + //trying to block shared memory + if (CShared::E_OK != CShared::Lock(CRASH_HANDLER_NAME, l_hSem, CRASH_LOCK_TIMEOUT)) + { + goto l_lblExit; + } + + l_bLock = TRUE; + + if (FALSE == CShared::Read(CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + goto l_lblExit; + } + + if (l_sCrash.qwTimeStamp == l_qwProcTime) + { + for (tUINT32 l_dwI = 0; l_dwI < CRASH_CLIENTS_COUNT; l_dwI++) + { + if (l_sCrash.pClients[l_dwI]) + { + l_sCrash.pClients[l_dwI]->Unshare(); + l_sCrash.pClients[l_dwI]->Close(); + } + } + } + else + { + l_bTimeError = TRUE; + } + +l_lblExit: + if (l_bTimeError) + { + CShared::UnLink(CRASH_HANDLER_NAME); + } + else + { + CShared::Close(l_sCrash.hShared); + } + + if (l_bLock) + { + CShared::UnLock(l_hSem); + } +}//P7_Exceptional_Flush + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Flush +//0) Lock crash memory +//1) Read crash memory +//2) Call every client crash functions +//3) - every client set "Error" flag to prevent ext. access (add data, add/del channel) +//4) - every client call crash function on every channel +//5) - some channels will dump stack back trace & exception info +//6) - every channel close connection & set "Error" flag +//7) - every client write/deliver all buffers +//8) - every client release shared memory +//9) unlock crash memory +//10) release crash memory +//11) leave function to execute def. handler +P7_EXPORT void __cdecl P7_Flush() +{ + tBOOL l_bLock = FALSE; + sCrash l_sCrash = {}; + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + tUINT64 l_qwProcTime = 0; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + + if (CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo)) + { + l_qwProcTime = ((tUINT64)l_uTimeHi << 32) + (tUINT64)l_uTimeLo; + } + + //////////////////////////////////////////////////////////////////////////// + //trying to block shared memory + if (CShared::E_OK != CShared::Lock(CRASH_HANDLER_NAME, l_hSem, CRASH_LOCK_TIMEOUT)) + { + goto l_lblExit; + } + + l_bLock = TRUE; + + if (FALSE == CShared::Read(CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + goto l_lblExit; + } + + if (l_sCrash.qwTimeStamp == l_qwProcTime) + { + for (tUINT32 l_dwI = 0; l_dwI < CRASH_CLIENTS_COUNT; l_dwI++) + { + if (l_sCrash.pClients[l_dwI]) + { + l_sCrash.pClients[l_dwI]->Flush(); + } + } + } + +l_lblExit: + if (l_bLock) + { + CShared::UnLock(l_hSem); + } +}//P7_Exceptional_Flush + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// Errors processing routines // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +struct stP7_Error_Thread +{ + tUINT32 uThreadId; + eP7_Error eError; +}; + +class CTreeThreadErrors: public CRBTree +{ +public: + virtual ~CTreeThreadErrors() { Clear(); } + +protected: + virtual tBOOL Data_Release(stP7_Error_Thread *i_pData) { free(i_pData); return TRUE; } + //Return TRUE - if (i_pKey < i_pData::key), FALSE - otherwise + tBOOL Is_Key_Less(tUINT32 i_pKey, stP7_Error_Thread *i_pData) { return (i_pKey < i_pData->uThreadId); } + //Return TRUE - if (i_pKey == i_pData::key), FALSE - otherwise + tBOOL Is_Qual(tUINT32 i_pKey, stP7_Error_Thread *i_pData) { return (i_pKey == i_pData->uThreadId); } +}; + + +static CTreeThreadErrors g_cErrorsTree; +static CLock g_cErrorLock; + +//////////////////////////////////////////////////////////////////////////////// +P7_EXPORT eP7_Error __cdecl P7_Last_Error() +{ + CLock l_cLock(&g_cErrorLock); + + eP7_Error l_eReturn = eP7_Error_None; + + stP7_Error_Thread *l_pError = g_cErrorsTree.Find(CProc::Get_Thread_Id()); + if (l_pError) + { + l_eReturn = l_pError->eError; + l_pError->eError = eP7_Error_None; + } + + return l_eReturn; +} + +//////////////////////////////////////////////////////////////////////////////// +void __cdecl P7_Set_Last_Error(eP7_Error i_eError) +{ + CLock l_cLock(&g_cErrorLock); + + tUINT32 l_uThreadId = CProc::Get_Thread_Id(); + + stP7_Error_Thread *l_pError = g_cErrorsTree.Find(l_uThreadId); + if (l_pError) + { + l_pError->eError = i_eError; + } + else + { + l_pError = (stP7_Error_Thread *)malloc(sizeof(stP7_Error_Thread)); + l_pError->eError = i_eError; + l_pError->uThreadId = l_uThreadId; + g_cErrorsTree.Push(l_pError, l_uThreadId); + } +} +}//extern "C" + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Argument_Text_Value +tXCHAR *Get_Argument_Text_Value(tXCHAR **i_pArgs, + tINT32 i_iCount, + const tXCHAR *i_pName + ) +{ + tXCHAR *l_pReturn = NULL; + + if ( (NULL == i_pName) + || (NULL == i_pArgs) + || (0 >= i_iCount) + ) + { + return l_pReturn; + } + + tUINT32 l_dwName_Lenght = PStrLen(i_pName); + tUINT32 i_dwArg_Lenght = 0; + + for(tINT32 l_iIDX = 0; l_iIDX < i_iCount; l_iIDX++) + { + i_dwArg_Lenght = PStrLen(i_pArgs[l_iIDX]); + + if ( (l_dwName_Lenght <= i_dwArg_Lenght) + && (0 == PStrNCmp(i_pArgs[l_iIDX], i_pName, l_dwName_Lenght)) + ) + { + l_pReturn = i_pArgs[l_iIDX] + l_dwName_Lenght; + break; + } + } + + return l_pReturn; +}//Get_Argument_Text_Value + + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// CClient +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +CClient::CClient(IP7_Client::eType i_eType, + tXCHAR **i_pArgs, + tINT32 i_iCount + ) + : m_lReference(1) + , m_eStatus(ECLIENT_STATUS_OK) + , m_hShared(NULL) + , m_bCrashMem(FALSE) + , m_pLog(NULL) + , m_bConnected(TRUE) + , m_dwConnection_Resets(0) + , m_eType(i_eType) + , m_pArgs(NULL) + , m_iArgsCnt(0) + , m_bFlushChannels(TRUE) + +{ + memset(m_pChannels, 0, sizeof(IP7C_Channel*)*USER_PACKET_CHANNEL_ID_MAX_SIZE); + memset(&m_hCS, 0, sizeof(m_hCS)); + memset(&m_hCS_Reg, 0, sizeof(m_hCS_Reg)); + + if ( (i_pArgs) + && (i_iCount) + ) + { + m_iArgsCnt = i_iCount; + m_pArgs = (tXCHAR **)malloc(sizeof(tXCHAR *) * m_iArgsCnt); + + if (m_pArgs) + { + for (int l_iI = 0; l_iI < m_iArgsCnt; l_iI ++) + { + m_pArgs[l_iI] = PStrDub(i_pArgs[l_iI]); + } + } + } + + + tXCHAR *l_pFlush = Get_Argument_Text_Value(m_pArgs, m_iArgsCnt, CLIENT_COMMAND_FLUSH_CHANNELS); + + if ( (NULL != l_pFlush) + && (TM('0') == l_pFlush[0]) + ) + { + m_bFlushChannels = FALSE; + } + + LOCK_CREATE(m_hCS_Reg); + LOCK_CREATE(m_hCS); + + Init_Log(i_pArgs, i_iCount); +}//CClient + + +//////////////////////////////////////////////////////////////////////////////// +//~CClient +CClient::~CClient() +{ + //remove log + if (m_pLog) + { + m_pLog->Release(); + m_pLog = NULL; + } + + if (m_pArgs) + { + for (int l_iI = 0; l_iI < m_iArgsCnt; l_iI ++) + { + PStrFreeDub(m_pArgs[l_iI]); + m_pArgs[l_iI] = NULL; + } + + free(m_pArgs); + m_pArgs = NULL; + m_iArgsCnt = 0; + } + + LOCK_DESTROY(m_hCS_Reg); + LOCK_DESTROY(m_hCS); +}//~CClient + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Status() +eClient_Status CClient::Get_Status() +{ + return m_eStatus; +}//Get_Status() + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Status +tBOOL CClient::Get_Status(sP7C_Status *o_pStatus) +{ + if (NULL == o_pStatus) + { + return FALSE; + } + + LOCK_ENTER(m_hCS); + o_pStatus->bConnected = m_bConnected; + o_pStatus->dwResets = m_dwConnection_Resets; + LOCK_EXIT(m_hCS); + + return TRUE; +}//Get_Status + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Type() +IP7_Client::eType CClient::Get_Type() +{ + return m_eType; +}//Get_Type() + + +//////////////////////////////////////////////////////////////////////////////// +//Add_Ref() +tINT32 CClient::Add_Ref() +{ + return ATOMIC_INC(&m_lReference); +}//Add_Ref() + + +//////////////////////////////////////////////////////////////////////////////// +//Release() +tINT32 CClient::Release() +{ + tINT32 l_lResult = ATOMIC_DEC(&m_lReference); + if ( 0 >= l_lResult ) + { + delete this; + } + + return l_lResult; +}//Release() + + +//////////////////////////////////////////////////////////////////////////////// +//Register_Channel() +eClient_Status CClient::Register_Channel(IP7C_Channel *i_pChannel) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_INTERNAL_ERROR; + + if (NULL == i_pChannel) + { + return ECLIENT_STATUS_WRONG_PARAMETERS; + } + + sP7C_Status l_sStatus = {FALSE, 0}; + + this->Get_Status(&l_sStatus); + + LOCK_ENTER(m_hCS_Reg); + + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (NULL == m_pChannels[l_dwI]) + { + sP7C_Channel_Info l_sInfo = {l_dwI}; + + m_pChannels[l_dwI] = i_pChannel; + + i_pChannel->On_Init(&l_sInfo); + i_pChannel->On_Status(l_dwI, &l_sStatus); + + l_eReturn = ECLIENT_STATUS_OK; + + break; + } + } + + LOCK_EXIT(m_hCS_Reg); + + return l_eReturn; +}//Register_Channel() + + +//////////////////////////////////////////////////////////////////////////////// +//Unregister_Channel() +eClient_Status CClient::Unregister_Channel(tUINT32 i_dwID) +{ + eClient_Status l_eReturn = ECLIENT_STATUS_OK; + + LOCK_ENTER(m_hCS_Reg); + + if ( (i_dwID >= USER_PACKET_CHANNEL_ID_MAX_SIZE) + || (NULL == m_pChannels[i_dwID]) + ) + { + l_eReturn = ECLIENT_STATUS_WRONG_PARAMETERS; + } + else + { + m_pChannels[i_dwID] = NULL; + } + + LOCK_EXIT(m_hCS_Reg); + + return l_eReturn; +}//Unregister_Channel() + + +//////////////////////////////////////////////////////////////////////////////// +//Share() +tBOOL CClient::Share(const tXCHAR *i_pName) +{ + tBOOL l_bReturn = FALSE; + + LOCK_ENTER(m_hCS_Reg); + + if (NULL == m_hShared) + { + tUINT32 l_dwLen1 = PStrLen(CLIENT_SHARED_PREFIX); + tUINT32 l_dwLen2 = PStrLen(i_pName); + tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); + + if (l_pName) + { + sObjShared l_stShared = {}; + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + tBOOL l_bCreate = TRUE; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + + PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, CLIENT_SHARED_PREFIX); + PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); + + JOURNAL_WARNING(m_pLog, TM("Shared memory {%s} registration error"), l_pName); + if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) + { + l_bCreate = FALSE; //it is already existing + + if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) + { + if ( (l_stShared.uProcTimeHi != l_uTimeHi) + || (l_stShared.uProcTimeLo != l_uTimeLo) + ) + { + JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp error, prev. session crashed or forget to release P7 objects?")); + CShared::UnLink(l_pName); + l_bCreate = TRUE; + } + } + CShared::UnLock(l_hSem); + } + + if (l_bCreate) + { + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + l_stShared.pPointer = static_cast(this); + l_stShared.uProcTimeHi = l_uTimeHi; + l_stShared.uProcTimeLo = l_uTimeLo; + l_bReturn = CShared::Create(&m_hShared, l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared)); + } + + free(l_pName); + l_pName = NULL; + } + } + + LOCK_EXIT(m_hCS_Reg); + + return l_bReturn; +}//Share() + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Argument() +const tXCHAR *CClient::Get_Argument(const tXCHAR *i_pName) +{ + return Get_Argument_Text_Value(m_pArgs, m_iArgsCnt, i_pName); +} + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Channels_Count() +size_t CClient::Get_Channels_Count() +{ + size_t l_szReturn = 0; + + LOCK_ENTER(m_hCS_Reg); + + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + l_szReturn ++; + } + } + LOCK_EXIT(m_hCS_Reg); + + return l_szReturn; +}//Get_Channels_Count() + + +//////////////////////////////////////////////////////////////////////////////// +//Get_Channel() +IP7C_Channel *CClient::Get_Channel(size_t i_szIndex) +{ + IP7C_Channel *l_pReturn = NULL; + size_t l_szCount = 0; + + LOCK_ENTER(m_hCS_Reg); + + for (tUINT32 l_dwI = 0; l_dwI < USER_PACKET_CHANNEL_ID_MAX_SIZE; l_dwI++) + { + if (m_pChannels[l_dwI]) + { + if (l_szCount == i_szIndex) + { + l_pReturn = m_pChannels[l_dwI]; + l_pReturn->Add_Ref(); + break; + } + else + { + l_szCount ++; + } + } + } + LOCK_EXIT(m_hCS_Reg); + + return l_pReturn; +}//Get_Channel() + + +//////////////////////////////////////////////////////////////////////////////// +//Unshare() +tBOOL CClient::Unshare() +{ + LOCK_ENTER(m_hCS_Reg); + if (m_hShared) + { + const tXCHAR *l_pName = CShared::GetName(m_hShared); + CShared::hSem l_hSem = SHARED_SEM_NULL; + + if ( (l_pName) + && (CShared::E_OK == CShared::Lock(l_pName, l_hSem, CRASH_LOCK_TIMEOUT)) + ) + { + CShared::Close(m_hShared); + m_hShared = NULL; + CShared::UnLock(l_hSem); + } + else + { + JOURNAL_ERROR(m_pLog, TM("Can't destroy shared memory")); + } + } + LOCK_EXIT(m_hCS_Reg); + + return TRUE; +}//Unshare() + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Log +eClient_Status CClient::Init_Log(tXCHAR **i_pArgs, tINT32 i_iCount) +{ + tXCHAR *l_pArg_Value = NULL; + IJournal::eLevel l_eVerbosity = IJournal::eLEVEL_CRITICAL; + + l_pArg_Value = Get_Argument_Text_Value(i_pArgs, i_iCount, + (const tXCHAR*)CLIENT_COMMAND_LOG_VERBOSITY + ); + if (NULL == l_pArg_Value) + { + goto l_lClean_Up; + } + + l_eVerbosity = (IJournal::eLevel)PStrToInt(l_pArg_Value); + + if (IJournal::eLEVEL_COUNT <= l_eVerbosity) + { + goto l_lClean_Up; + } + + + m_pLog = new CJournal(); + + if (m_pLog) + { + if (FALSE == m_pLog->Initialize(TM("P7.Logs\\"))) + { + m_pLog->Release(); + m_pLog = NULL; + } + else + { + m_pLog->Set_Verbosity(l_eVerbosity); + } + } + +l_lClean_Up: + + return ECLIENT_STATUS_OK; +}//Init_Log + + + +//////////////////////////////////////////////////////////////////////////////// +//Init_Crash_Handler() +//1) lock shared memory (infinite) +// - success - goto 5 +// - failed - goto 2 +//------------------------------------ +//2) Fill sCrash structure +//3) Try to create&write shared memory +// - success - register Signal & exit +// - failed - goto 4 +//------------------------------------ +//4) lock shared memory (infinite) +// - success - goto 5 +// - failed - exit, it is error +//------------------------------------ +//5) Read shared memory (without lock) +//6) Update shared memory by new client +//7) increment reference counter +//8) write back shared memory +//9) Unlock shared memory + +eClient_Status CClient::Init_Crash_Handler(tXCHAR **i_pArgs, tINT32 i_iCount) +{ + CShared::eLock l_eLock = CShared::E_OK; + tBOOL l_bResult = FALSE; + sCrash l_sCrash; //not initialized here + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + tUINT64 l_qwProcTime = 0; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + UNUSED_ARG(i_pArgs); + UNUSED_ARG(i_iCount); + + if (CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo)) + { + l_qwProcTime = ((tUINT64)l_uTimeHi << 32) + (tUINT64)l_uTimeLo; + } + + //////////////////////////////////////////////////////////////////////////// + //trying to block shared memory + l_eLock = CShared::Lock(CRASH_HANDLER_NAME, l_hSem, CRASH_LOCK_TIMEOUT); //5 minutes + + if (CShared::E_OK == l_eLock) + { + //if we are here it mean we are successfully get lock and now we need to read + //memory, update it and release lock + if (CShared::Read(CRASH_HANDLER_NAME, (tUINT8*)&l_sCrash, (tUINT16)sizeof(l_sCrash))) + { + if (l_sCrash.qwTimeStamp == l_qwProcTime) + { + for (tUINT32 l_dwI = 0; l_dwI < CRASH_CLIENTS_COUNT; l_dwI++) + { + if (NULL == l_sCrash.pClients[l_dwI]) + { + l_sCrash.pClients[l_dwI] = this; + l_sCrash.lReference ++; + l_bResult = TRUE; + break; + } + } + + //no free room in shared memory, exit ! + if (l_bResult) + { + if (FALSE == CShared::Write(CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + JOURNAL_ERROR(m_pLog, TM("Can't write to crash shared memory")); + l_bResult = FALSE; + } + } + else + { + JOURNAL_ERROR(m_pLog, TM("There is no free space for client")); + } + } + else + { + JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp missmatch, it wasn't closed properly last time?")); + CShared::UnLink(CRASH_HANDLER_NAME); + l_eLock = CShared::E_NOT_EXISTS; //going to create new shared memory space + } + } + else + { + JOURNAL_ERROR(m_pLog, TM("Can't read crash shared memory")); + } + + CShared::UnLock(l_hSem); + } //if (CShared::E_OK == l_eLock) + + if (CShared::E_NOT_EXISTS == l_eLock) + { + //it is not exists - create new one///////////////////////////////////// + memset(&l_sCrash, 0, sizeof(l_sCrash)); + l_sCrash.lReference = 1; + l_sCrash.qwTimeStamp = l_qwProcTime; + l_sCrash.pClients[0] = this; + + JOURNAL_INFO(m_pLog, TM("Try to create shared lock")); + + if (CShared::Create(&l_sCrash.hShared, + CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + //successful creation of shared memory///////////////////////////// + JOURNAL_INFO(m_pLog, TM("Register new crash handler")); + l_bResult = TRUE; + } + else //creation of shared memory failed + { + JOURNAL_WARNING(m_pLog, TM("CShared::Create failed, try to lock")); + //it wasn't possible to create shared memory, possibly it was created + //by somebody else, trying to get lock + l_eLock = CShared::Lock(CRASH_HANDLER_NAME, l_hSem, CRASH_LOCK_TIMEOUT); //5 minutes + if (CShared::E_OK == l_eLock) + { + //if we are here it mean we are successfully get lock and now we need to read + //memory, update it and release lock + if (CShared::Read(CRASH_HANDLER_NAME, (tUINT8*)&l_sCrash, (tUINT16)sizeof(l_sCrash))) + { + if (l_sCrash.qwTimeStamp == l_qwProcTime) + { + for (tUINT32 l_dwI = 0; l_dwI < CRASH_CLIENTS_COUNT; l_dwI++) + { + if (NULL == l_sCrash.pClients[l_dwI]) + { + l_sCrash.pClients[l_dwI] = this; + l_sCrash.lReference ++; + l_bResult = TRUE; + break; + } + } + + //no free room in shared memory, exit ! + if (l_bResult) + { + if (FALSE == CShared::Write(CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + JOURNAL_ERROR(m_pLog, TM("Can't write to crash shared memory")); + l_bResult = FALSE; + } + } + } + else //if (l_sCrash.qwTimeStamp != l_qwProcTime) + { + JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp missmatch, it wasn't closed properly last time?")); + CShared::UnLink(CRASH_HANDLER_NAME); + l_eLock = CShared::E_NOT_EXISTS; //going to create new shared memory space + } + } + else + { + JOURNAL_ERROR(m_pLog, TM("Can't read crash shared memory")); + l_bResult = FALSE; + } + + CShared::UnLock(l_hSem); + } + else + { + JOURNAL_ERROR(m_pLog, TM("Can't get lock for crash handler")); + l_bResult = FALSE; + } + } + } //if (CShared::E_NOT_EXISTS == l_eLock) + else if (CShared::E_OK != l_eLock) + { + //if it is internal errors////////////////////////////////////////////// + JOURNAL_ERROR(m_pLog, TM("Can't get lock for crash handler")); + l_bResult = FALSE; + } + + if (l_bResult) + { + LOCK_ENTER(m_hCS_Reg); + m_bCrashMem = TRUE; + LOCK_EXIT(m_hCS_Reg); + } + + return ECLIENT_STATUS_OK; +}//Init_Crash_Handler + + +//////////////////////////////////////////////////////////////////////////////// +//Del_Crash_Handler() +//1) lock shared memory (infinite) +// - success - goto 2 +// - failed - exit +//2) Read shared memory +//3) find client and clear pointer +//4) decrease reference counter +//5) if reference counter = 0 delete shared memory & unregister signal +//6) unlock shared memory (if memory was deleted - it will just return error) +eClient_Status CClient::Uninit_Crash_Handler() +{ + tBOOL l_bReturn = FALSE; + tBOOL l_bLock = FALSE; + tBOOL l_bCrashMem = FALSE; + sCrash l_sCrash; //not initialized here + CShared::hSem l_hSem = SHARED_SEM_NULL; + + LOCK_ENTER(m_hCS_Reg); + l_bCrashMem = m_bCrashMem; + LOCK_EXIT(m_hCS_Reg); + + if (FALSE == l_bCrashMem) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //trying to block shared memory + if (CShared::E_OK != CShared::Lock(CRASH_HANDLER_NAME, l_hSem, CRASH_LOCK_TIMEOUT)) + { + JOURNAL_ERROR(m_pLog, TM("Can't get lock for crash handler")); + l_bReturn = FALSE; + goto l_lblExit; + } + + l_bLock = TRUE; + + if (FALSE == CShared::Read(CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + JOURNAL_ERROR(m_pLog, TM("Can't read from crash shared memory")); + l_bReturn = FALSE; + goto l_lblExit; + } + + for (tUINT32 l_dwI = 0; l_dwI < CRASH_CLIENTS_COUNT; l_dwI++) + { + if (this == l_sCrash.pClients[l_dwI]) + { + l_sCrash.pClients[l_dwI] = NULL; + l_bReturn = TRUE; + l_sCrash.lReference --; + break; + } + } + + //client is not found + if (FALSE == l_bReturn) + { + goto l_lblExit; + } + + if (l_sCrash.lReference) + { + if (FALSE == CShared::Write(CRASH_HANDLER_NAME, + (tUINT8*)&l_sCrash, + (tUINT16)sizeof(l_sCrash) + ) + ) + { + JOURNAL_ERROR(m_pLog, TM("Can't write to crash shared memory")); + l_bReturn = FALSE; + goto l_lblExit; + } + } + else + { + CShared::Close(l_sCrash.hShared); + } + +l_lblExit: + + if (l_bLock) + { + CShared::UnLock(l_hSem); + } + + return ECLIENT_STATUS_OK; +}//Del_Crash_Handler() + + diff --git a/p7lib/Sources/Client.h b/p7lib/Sources/Client.h new file mode 100644 index 0000000..e868801 --- /dev/null +++ b/p7lib/Sources/Client.h @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide base client functionality / +//////////////////////////////////////////////////////////////////////////////// +#ifndef CLIENT_H +#define CLIENT_H + +tXCHAR *Get_Argument_Text_Value(tXCHAR **i_pArgs, + tINT32 i_iCount, + const tXCHAR *i_pName + ); + + + +//////////////////////////////////////////////////////////////////////////////// +//CClient +class CClient: + public IP7_Client +{ +protected: + //put volatile variables at the top, to obtain 32 bit alignment. + //Project has 8 bytes alignment by default + tINT32 volatile m_lReference; + volatile eClient_Status m_eStatus; + tLOCK m_hCS_Reg; + tLOCK m_hCS; + IP7C_Channel *m_pChannels[USER_PACKET_CHANNEL_ID_MAX_SIZE]; + CShared::hShared m_hShared; + tBOOL m_bCrashMem; + IJournal *m_pLog; + tBOOL m_bConnected; + tUINT32 m_dwConnection_Resets; + IP7_Client::eType m_eType; + tXCHAR **m_pArgs; + tINT32 m_iArgsCnt; + volatile tBOOL m_bFlushChannels; + +public: + CClient(IP7_Client::eType i_eType, + tXCHAR **i_pArgs, + tINT32 i_iCount + ); + virtual ~CClient(); + +public: + virtual IP7_Client::eType Get_Type(); + + virtual tINT32 Add_Ref(); + virtual tINT32 Release(); + + virtual eClient_Status Get_Status(); + virtual tBOOL Get_Status(sP7C_Status *o_pStatus); + //virtual tBOOL Get_Info(sP7C_Info *o_pInfo); + + virtual eClient_Status Register_Channel(IP7C_Channel *i_pChannel); + virtual eClient_Status Unregister_Channel(tUINT32 i_dwID); + + //virtual eClient_Status Sent(tUINT32 i_dwChannel_ID, + // sP7C_Data_Chunk *i_pChunks, + // tUINT32 i_dwCount, + // tUINT32 i_dwSize); + + virtual tBOOL Share(const tXCHAR *i_pName); + + virtual const tXCHAR *Get_Argument(const tXCHAR *i_pName); + + virtual size_t Get_Channels_Count(); + virtual IP7C_Channel *Get_Channel(size_t i_szIndex); + + virtual tBOOL Unshare(); + + //reimplemented in childes, will be called in case of process crash + virtual tBOOL Close() = 0; + +protected: + eClient_Status Init_Log(tXCHAR **i_pArgs, tINT32 i_iCount); + + eClient_Status Init_Crash_Handler(tXCHAR **i_pArgs, tINT32 i_iCount); + eClient_Status Uninit_Crash_Handler(); +}; + + +#endif //CLIENT_H diff --git a/p7lib/Sources/Common.h b/p7lib/Sources/Common.h new file mode 100644 index 0000000..756d23b --- /dev/null +++ b/p7lib/Sources/Common.h @@ -0,0 +1,58 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef COMMON_H +#define COMMON_H + +// Including SDKDDKVer.h defines the highest available Windows platform. +// If you wish to build your application for a previous Windows platform, include +// WinSDKVer.h and set the _WIN32_WINNT macro to the platform you wish to support +// before including SDKDDKVer.h. +#include +#include +#include +#include +#include + + +#include "GTypes.h" + +#include "Length.h" + +#include "PAtomic.h" +#include "PLock.h" +#include "PString.h" +#include "PTime.h" +#include "Ticks.h" +#include "IMEvent.h" +#include "PMEvent.h" +#include "PThreadShell.h" +#include "RBTree.h" +#include "AList.h" +#include "PShared.h" + +#include "UTF.h" +#include "PString.h" +#include "WString.h" +#include "PFileSystem.h" + +#include "PProcess.h" +#include "IJournal.h" +#include "PJournal.h" + +#endif //COMMON_H diff --git a/p7lib/Sources/CommonClient.h b/p7lib/Sources/CommonClient.h new file mode 100644 index 0000000..519e084 --- /dev/null +++ b/p7lib/Sources/CommonClient.h @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#ifndef COMMONCLIENT_H +#define COMMONCLIENT_H + +// Linux: +//#include +//#include +//#include +//#include +//#include +//#include + + +//////////////////////////////////////////////////////////////////////////////// +//Independent +#include "Common.h" + +#include "UDP_NB.h" + +#include "PSystem.h" + +#include "Lock.h" + +#include "P7_Client.h" +//because USER_PACKET_CHANNEL_ID_MAX_SIZE defined in "P7_Client.h". + +#include "CRC32.h" //used only in TPackets + +#include "TPackets.h" +#include "PacketsPool.h" +#include "Client.h" + +#include "P7_Telemetry.h" +#include "P7_Trace.h" +#include "P7_Extensions.h" + + +//////////////////////////////////////////////////////////////////////////////// +//CUintList +class CUintList + : public CListPool +{ +protected: + virtual tBOOL Data_Release(tUINT32 i_pData) + { + UNUSED_ARG(i_pData); + return TRUE; + } +}; + +struct sObjShared +{ + void *pPointer; + tUINT32 uProcTimeHi; + tUINT32 uProcTimeLo; +}; + +extern "C" void __cdecl P7_Set_Last_Error(eP7_Error i_eError); + +#endif //COMMONCLIENT_H diff --git a/p7lib/Sources/Formatter.h b/p7lib/Sources/Formatter.h new file mode 100644 index 0000000..1ee0ca4 --- /dev/null +++ b/p7lib/Sources/Formatter.h @@ -0,0 +1,1337 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality of text formatting using var. args. / +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FORMATTER_H +#define FORMATTER_H + +#include + +#define FORMATTER_NO_WIDTH 0 +#define FORMATTER_ARG_WIDTH -1 + +#define FORMATTER_NO_PRECISION 0 +#define FORMATTER_ARG_PRECISION -1 + +#define FORMATTER_MAX_WIDTH 1024 + +#ifndef min + #define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#if !defined(UINTMAX_MAX) + typedef uint64_t uintmax_t; + #define UINTMAX_MAX 0xffffffffffffffffU +#endif + +#if !defined(INTMAX_MAX) + typedef int64_t intmax_t; + #define INTMAX_MIN (-0x7fffffffffffffff - 1) + #define INTMAX_MAX 0x7fffffffffffffff +#endif + + +#if !defined(min) + #define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +//////////////////////////////////////////////////////////////////////////////// +class CFormatter +{ +public: + //////////////////////////////////////////////////////////////////////////// + struct sBuffer + { + tINT32 volatile lReference; + tXCHAR *pBuffer; + size_t szBuffer; + + //////////////////////////////////////////////////////////////////////// + sBuffer(size_t i_szBuffer) + : lReference(1) + , pBuffer(NULL) + , szBuffer(i_szBuffer) + { + if (szBuffer) + { + szBuffer = 256; + } + + pBuffer = (tXCHAR*)malloc(szBuffer * sizeof(tXCHAR)); + } + + //////////////////////////////////////////////////////////////////////// + tBOOL Realloc(size_t i_szSize) + { + tXCHAR *l_pTmp = (tXCHAR*)realloc(pBuffer, i_szSize * sizeof(tXCHAR)); + if (l_pTmp) + { + pBuffer = l_pTmp; + szBuffer = i_szSize; + return TRUE; + } + + return FALSE; + } + + //////////////////////////////////////////////////////////////////////// + virtual tINT32 Add_Ref() + { + return ATOMIC_INC(&lReference); + } + + //////////////////////////////////////////////////////////////////////// + virtual tINT32 Release() + { + tINT32 l_lResult = ATOMIC_DEC(&lReference); + if ( 0 >= l_lResult ) + { + delete this; + } + + return l_lResult; + } + + protected: + //////////////////////////////////////////////////////////////////////// + virtual ~sBuffer() + { + if (pBuffer) + { + free(pBuffer); + pBuffer = NULL; + } + szBuffer = 0; + } + };//struct sBuffer + +protected: + union uValue + { + tINT8 i8; + tUINT8 u8; + tINT16 i16; + tUINT16 u16; + tINT32 i32; + tUINT32 u32; + tINT64 i64; + tUINT64 u64; + intmax_t iMax; + uintmax_t uMax; + tDOUBLE d64; + tUINT8 pData[32]; + }; + + enum eSize + { + eSize32, + eSize64, + eSizehh, + eSizeh, + eSizew, + eSizeL, + eSizell, + eSizel, + eSizeI, + eSizez, + eSizej, + eSizet, + eSizeUnk + }; + + enum eType + { + eTypeDouble, + eTypeString, + eTypeChar, + eTypeIntDec, + eTypeUintDec, + eTypeUintHex, + eTypeUintHEX, + eTypeUintOct, + eTypePointer, + eTypeUintBin, + eTypeNone, + + eTypeMax + }; + + //////////////////////////////////////////////////////////////////////////// + struct sArg + { + tBOOL bFlagLeftAlign; + tBOOL bFlagSign; + tBOOL bFlagGrid; + tXCHAR cPadding; + tXCHAR *pPrefix; + size_t szPrefix; + CFormatter::eSize eSize; + CFormatter::eType eType; + tINT32 iWidth; //0 - no width, -1 - use argument to specify width + tINT32 iPrecision; //-2 no precision, -1 - use argument to specify precision + tXCHAR *pDouble; //format string for double + sArg *pNext; + + //////////////////////////////////////////////////////////////////////// + sArg() + { + bFlagLeftAlign = bFlagSign = bFlagGrid = FALSE; + cPadding = TM(' '); + pPrefix = NULL; + szPrefix = 0; + eSize = eSizeUnk; + eType = eTypeNone; + iWidth = FORMATTER_NO_WIDTH; + iPrecision = FORMATTER_NO_PRECISION; + pDouble = NULL; + pNext = NULL; + } + + //////////////////////////////////////////////////////////////////////// + ~sArg() + { + if (pPrefix) + { + free(pPrefix); + pPrefix = NULL; + } + + if (pDouble) + { + free(pDouble); + pDouble = NULL; + } + + if (pNext) + { + delete pNext; + pNext = NULL; + } + } + };//sArg + + sArg *m_pArgHead; + sBuffer *m_pBuffer; + sP7Trace_Arg *m_pArgs; + size_t m_szArgs; + tBOOL m_bError; + tBOOL m_bLittleEndian; +public: + //////////////////////////////////////////////////////////////////////////// + //CFormatter + CFormatter(const tXCHAR *i_pFormat, + sP7Trace_Arg *i_pArgs, + size_t i_szArgs, + CFormatter::sBuffer *i_pBuffer = NULL + ) + : m_pArgHead(NULL) + , m_pBuffer(i_pBuffer) + , m_pArgs(i_pArgs) + , m_szArgs(i_szArgs) + , m_bError(FALSE) + , m_bLittleEndian(TRUE) + { + const tXCHAR *l_pCursor = i_pFormat; + const tXCHAR *l_pHead = i_pFormat; + const tXCHAR *l_pPercent = i_pFormat; + sArg *l_pTail = NULL; + sArg *l_pArg = NULL; + size_t l_szArgs = 0; + + if (!m_pBuffer) + { + m_pBuffer = new sBuffer(1024); + } + else + { + m_pBuffer->Add_Ref(); + } + + while (*l_pCursor) + { + if (TM('%') == *l_pCursor) + { + l_pCursor++; + + if (TM('%') != *l_pCursor) + { + l_pPercent = l_pCursor - 1; + l_pArg = AddArg(l_pHead, (size_t)(l_pCursor - l_pHead - 1)); + } + } + + if (l_pArg) + { + /////////////////////////////////////////////////////////////// + //Flags + while (1) //check flags + { + if (TM('+') == *l_pCursor) + { + l_pArg->bFlagSign = TRUE; + l_pCursor++; + } + else if (TM('-') == *l_pCursor) + { + l_pArg->bFlagLeftAlign = TRUE; + l_pCursor++; + } + else if (TM(' ') == *l_pCursor) + { + l_pCursor++; + } + else if (TM('#') == *l_pCursor) + { + l_pArg->bFlagGrid = TRUE; + l_pCursor++; + } + else if (TM('0') == *l_pCursor) + { + l_pArg->cPadding = TM('0'); + l_pCursor++; + } + else if (TM('\'') == *l_pCursor) + { + //ignored for a while + } + else + { + break; + } + } + + /////////////////////////////////////////////////////////////// + //width + tINT32 l_iWidth = 0; + + if (TM('*') == *l_pCursor) + { + l_iWidth = FORMATTER_ARG_WIDTH; + l_pCursor ++; + } + else while ( (TM('0') <= *l_pCursor) + && (TM('9') >= *l_pCursor) + ) + { + l_iWidth = l_iWidth * 10 + ((*l_pCursor) - TM('0')); + l_pCursor++; + } + + if (0 != l_iWidth) + { + l_pArg->iWidth = l_iWidth; + } + + /////////////////////////////////////////////////////////////// + //precision + if (TM('.') == *l_pCursor) + { + l_pCursor ++; + + if (TM('*') == *l_pCursor) + { + l_pArg->iPrecision = FORMATTER_ARG_PRECISION; + l_pCursor ++; + } + else + { + tINT32 l_iPrecision = 0; + while ( (TM('0') <= *l_pCursor) + && (TM('9') >= *l_pCursor) + ) + { + l_iPrecision = l_iPrecision * 10 + ((*l_pCursor) - TM('0')); + l_pCursor++; + } + + if (l_iPrecision) + { + l_pArg->iPrecision = l_iPrecision; + } + } + } + + /////////////////////////////////////////////////////////////// + //size + l_pArg->eSize = GetSize(l_pCursor); + + /////////////////////////////////////////////////////////////// + //type + tBOOL l_bFound = FALSE; + if ( (TM('d') == *l_pCursor) + || (TM('i') == *l_pCursor) + ) + { + l_pArg->eType = eTypeIntDec; + l_bFound = TRUE; + } + else if (TM('x') == *l_pCursor) + { + l_pArg->eType = eTypeUintHex; + l_bFound = TRUE; + } + else if (TM('X') == *l_pCursor) + { + l_pArg->eType = eTypeUintHEX; + l_bFound = TRUE; + } + else if (TM('u') == *l_pCursor) + { + l_pArg->eType = eTypeUintDec; + l_bFound = TRUE; + } + else if ( (TM('c') == *l_pCursor) + || (TM('C') == *l_pCursor) + ) + { + l_pArg->eType = eTypeChar; + l_bFound = TRUE; + } + else if ( (TM('s') == *l_pCursor) + || (TM('S') == *l_pCursor) + ) + { + l_pArg->eType = eTypeString; + l_bFound = TRUE; + } + else if (TM('b') == *l_pCursor) + { + l_pArg->eType = eTypeUintBin; + l_bFound = TRUE; + } + else if ( (TM('a') == *l_pCursor) + || (TM('A') == *l_pCursor) + || (TM('f') == *l_pCursor) + || (TM('e') == *l_pCursor) + || (TM('E') == *l_pCursor) + || (TM('g') == *l_pCursor) + || (TM('G') == *l_pCursor) + ) + { + size_t l_szLength = (size_t)(l_pCursor - l_pPercent + 2); + l_pArg->pDouble = (tXCHAR*)malloc(l_szLength * sizeof(tXCHAR)); + if (l_pArg->pDouble) + { + memcpy(l_pArg->pDouble, l_pPercent, (l_szLength - 1) * sizeof(tXCHAR)); + l_pArg->pDouble[l_szLength - 1] = 0; + } + l_bFound = TRUE; + l_pArg->eType = eTypeDouble; + } + else if (TM('o') == *l_pCursor) + { + l_pArg->eType = eTypeUintOct; + l_bFound = TRUE; + } + else if (TM('p') == *l_pCursor)//(TM('n') == *l_pCursor) ->>Ignored, not supported + { + l_pArg->bFlagGrid = TRUE; + l_pArg->eType = eTypePointer; + l_bFound = TRUE; + } + + if (l_bFound) + { + l_szArgs ++; + + if (FORMATTER_ARG_PRECISION == l_pArg->iPrecision) l_szArgs ++; + if (FORMATTER_ARG_WIDTH == l_pArg->iWidth) l_szArgs ++; + + l_pHead = l_pCursor + 1; + if (!l_pTail) + { + m_pArgHead = l_pArg; + } + else + { + l_pTail->pNext = l_pArg; + } + + l_pTail = l_pArg; + l_pCursor++; + } + else if (l_pArg) + { + delete l_pArg; + } + + l_pArg = NULL; + }//if (l_pArg) + else + { + l_pCursor++; + } + } + + if (l_pArg) + { + delete l_pArg; + l_pArg = NULL; + } + + if (l_pCursor != l_pHead) + { + l_pArg = AddArg(l_pHead, (size_t)(l_pCursor - l_pHead)); + + if (!l_pTail) + { + m_pArgHead = l_pArg; + } + else + { + l_pTail->pNext = l_pArg; + } + } + + if (l_szArgs != m_szArgs) + { + m_bError = TRUE; + } + }//CFormatter + + //////////////////////////////////////////////////////////////////////////// + //~CFormatter + virtual ~CFormatter() + { + if (m_pArgHead) + { + delete m_pArgHead; + m_pArgHead = NULL; + } + + if (m_pBuffer) + { + m_pBuffer->Release(); + m_pBuffer = NULL; + } + + m_pArgs = NULL; + m_szArgs = 0; + }//~CFormatter + + //////////////////////////////////////////////////////////////////////////// + //EnableBigEndian + void EnableBigEndian() + { + m_bLittleEndian = FALSE; + } + +#define FORMAT_SIGN\ + if (l_bMinus) {*l_pIter++ = TM('-');}\ + else if (l_pArg->bFlagSign) {*l_pIter++ = TM('+');}\ + +#define FORMAT_X_PREFIX\ + if (l_pArg->bFlagGrid) {*l_pIter++ = TM('0'); *l_pIter++ = TM('x');}\ + +#define FORMAT_0_PREFIX\ + if (l_pArg->bFlagGrid) {*l_pIter++ = TM('0');}\ + +#define FORMAT_B_PREFIX\ + if (l_pArg->bFlagGrid) {*l_pIter++ = TM('b');}\ + + +#define FORMAT_NO_SIGN +#define FORMAT_NO_PREFIX + +#define FORMAT_DIGIT(i_uBase, i_pDigits, SIGN_MACRO, PREFIX_MACRO)\ + l_pDigit = m_pBuffer->pBuffer + m_pBuffer->szBuffer - 1;\ + l_pTail = l_pDigit;\ + *l_pDigit = TM('0');\ + if (l_uValue.uMax) l_pDigit++;\ + while(l_uValue.uMax)\ + {\ + *(--l_pDigit) = *(i_pDigits + (size_t)(l_uValue.uMax % i_uBase));\ + l_uValue.uMax /= i_uBase;\ + }\ + l_szAdd = (size_t)(l_pTail - l_pDigit + 1);\ + l_iPrecision -= (tINT32)l_szAdd;\ + l_iWidth -= (tINT32)l_szAdd;\ + if (0 < l_iPrecision) l_iWidth -= l_iPrecision;\ + if (0 < l_iWidth) l_szAdd += l_iWidth;\ + if (0 < l_iPrecision) l_szAdd += l_iPrecision;\ + if ((l_szReturn + l_szAdd + 8) >= i_szBuffer)\ + {\ + l_bError = TRUE;\ + break;\ + }\ + l_pIter = o_pBuffer + l_szReturn;\ + if (FALSE == l_pArg->bFlagLeftAlign)\ + {\ + if (TM(' ') == l_pArg->cPadding)\ + {\ + while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; \ + }\ + SIGN_MACRO\ + PREFIX_MACRO\ + if (TM('0') == l_pArg->cPadding)\ + {\ + while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; \ + }\ + while (0 < l_iPrecision--) *l_pIter++ = TM('0'); \ + l_szAdd = (size_t)(l_pTail - l_pDigit + 1);\ + memcpy(l_pIter, l_pDigit, sizeof(tXCHAR) * l_szAdd);\ + l_pIter += l_szAdd;\ + }\ + else\ + {\ + SIGN_MACRO\ + PREFIX_MACRO\ + while (0 < l_iPrecision--) *l_pIter++ = TM('0'); \ + if (TM('0') == l_pArg->cPadding)\ + {\ + while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; \ + }\ + l_szAdd = (size_t)(l_pTail - l_pDigit + 1);\ + memcpy(l_pIter, l_pDigit, sizeof(tXCHAR) * l_szAdd);\ + l_pIter += l_szAdd;\ + if (TM(' ') == l_pArg->cPadding)\ + {\ + while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; \ + }\ + }\ + l_szReturn = (size_t)(l_pIter - o_pBuffer);\ +//#define FORMAT_DIGIT + +#define COPY_STR(SRC_TYPE, DST_TYPE)\ + l_pIter = o_pBuffer + l_szReturn;\ + l_pTail = o_pBuffer + i_szBuffer - 4;\ + l_iReturn = 0;\ + while (*(SRC_TYPE*)i_pValues)\ + {\ + if ((l_pTail - l_pIter) > 2)\ + {\ + *l_pIter++ = (DST_TYPE)*(SRC_TYPE*)i_pValues; \ + l_iReturn++;\ + }\ + else\ + {\ + l_iReturn = -1;\ + break;\ + }\ + i_pValues += sizeof(SRC_TYPE);\ + }\ + i_pValues += sizeof(SRC_TYPE);\ +//#define COPY_STR + +#define COPY_ARG(DstVar, SrcSignificantSize, SrcTotalSize)\ + if (m_bLittleEndian)\ + {\ + memcpy(&(DstVar), i_pValues, min((SrcSignificantSize), (SrcTotalSize)));\ + }\ + else\ + {\ + memcpy(((tUINT8*)&(DstVar)) + (sizeof(DstVar) - (SrcSignificantSize)), \ + i_pValues + ((SrcTotalSize) - (SrcSignificantSize)), \ + SrcSignificantSize\ + );\ + }\ +//#define COPY_ARG + + //////////////////////////////////////////////////////////////////////////// + //Format + tINT32 Format(tXCHAR *o_pBuffer, + size_t i_szBuffer, + const tUINT8 *i_pValues + ) + { + const static tXCHAR g_pHEX[] = TM("0123456789ABCDEF"); + const static tXCHAR g_pHex[] = TM("0123456789abcdef"); + const static size_t g_pSize[P7TRACE_ARGS_COUNT] = {0, //P7TRACE_ARG_TYPE_UNK + 1, //P7TRACE_ARG_TYPE_CHAR, P7TRACE_ARG_TYPE_INT8 + 2, //P7TRACE_ARG_TYPE_CHAR16 + 2, //P7TRACE_ARG_TYPE_INT16 + 4, //P7TRACE_ARG_TYPE_INT32 + 8, //P7TRACE_ARG_TYPE_INT64 + 8, //P7TRACE_ARG_TYPE_DOUBLE + 0, //P7TRACE_ARG_TYPE_PVOID + 0, //P7TRACE_ARG_TYPE_USTR16 + 0, //P7TRACE_ARG_TYPE_STRA + 0, //P7TRACE_ARG_TYPE_USTR8 + 0, //P7TRACE_ARG_TYPE_USTR32 + 4, //P7TRACE_ARG_TYPE_CHAR32 + sizeof(uintmax_t), //P7TRACE_ARG_TYPE_INTMAX + }; + + sP7Trace_Arg *l_pP7Args = m_pArgs; + size_t l_szReturn = 0; + tBOOL l_bError = FALSE; + sArg *l_pArg = m_pArgHead; + tINT32 l_iWidth; + tINT32 l_iPrecision; + uValue l_uValue; + tXCHAR *l_pDigit; + tXCHAR *l_pTail; + tXCHAR *l_pIter; + size_t l_szAdd; + + if (m_bError) + { + return PSPrint(o_pBuffer, i_szBuffer, TM("Format string error")); + } + + while(l_pArg) + { + //Copy text prefix + if (l_pArg->pPrefix) + { + if ((l_szReturn + l_pArg->szPrefix) < i_szBuffer) + { + memcpy(o_pBuffer + l_szReturn, l_pArg->pPrefix, l_pArg->szPrefix * sizeof(tXCHAR)); + l_szReturn += l_pArg->szPrefix; + } + else + { + l_bError = TRUE; + break; + } + } + + //Retrieving width and precision + l_iWidth = l_pArg->iWidth; + l_iPrecision = l_pArg->iPrecision; + + if (FORMATTER_ARG_WIDTH == l_iWidth) + { + COPY_ARG(l_iWidth, sizeof(tINT32), l_pP7Args->bSize); + i_pValues += l_pP7Args->bSize; + l_pP7Args ++; + + if (0 > l_iWidth) + { l_iWidth = 0; } + else if (FORMATTER_MAX_WIDTH < l_iWidth) + { l_iWidth = FORMATTER_MAX_WIDTH;} + } + if (FORMATTER_ARG_PRECISION == l_iPrecision) + { + COPY_ARG(l_iPrecision, sizeof(tINT32), l_pP7Args->bSize); + i_pValues += l_pP7Args->bSize; + l_pP7Args ++; + if (0 > l_iPrecision) + { l_iPrecision = 0; } + else if (FORMATTER_MAX_WIDTH < l_iPrecision) + { l_iPrecision = FORMATTER_MAX_WIDTH;} + } + + if (eTypeIntDec == l_pArg->eType) + { + tBOOL l_bMinus = FALSE; + if (P7TRACE_ARG_TYPE_INT32 == l_pP7Args->bType) + { + tINT32 l_iVal = 0; + COPY_ARG(l_iVal, sizeof(tINT32), l_pP7Args->bSize); + l_uValue.iMax = l_iVal; + } + else if (P7TRACE_ARG_TYPE_INT64 == l_pP7Args->bType) + { + tINT64 l_iVal = 0ll; + COPY_ARG(l_iVal, sizeof(tINT64), l_pP7Args->bSize); + l_uValue.iMax = l_iVal; + } + else if (P7TRACE_ARG_TYPE_INT16 == l_pP7Args->bType) + { + tINT16 l_iVal = 0; + COPY_ARG(l_iVal, sizeof(tINT16), l_pP7Args->bSize); + l_uValue.iMax = l_iVal; + } + else if (P7TRACE_ARG_TYPE_INT8 == l_pP7Args->bType) + { + tINT8 l_iVal = 0; + COPY_ARG(l_iVal, sizeof(tINT8), l_pP7Args->bSize); + l_uValue.iMax = l_iVal; + } + else //if (P7TRACE_ARG_TYPE_INTMAX == l_pP7Args->bType) + { + intmax_t l_iVal = 0ll; + memcpy(&l_iVal, i_pValues, min(g_pSize[l_pP7Args->bType], l_pP7Args->bSize)); + l_uValue.iMax = l_iVal; + } + + if (0 > l_uValue.iMax) + { + l_bMinus = TRUE; + l_iWidth --; + l_uValue.iMax = -l_uValue.iMax; + } + + if (l_pArg->bFlagSign) l_iWidth --; + + FORMAT_DIGIT(10ull, g_pHEX, FORMAT_SIGN, FORMAT_NO_PREFIX); + } + else if (eTypeUintDec == l_pArg->eType) + { + l_uValue.uMax = 0ull; + COPY_ARG(l_uValue.uMax, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + FORMAT_DIGIT(10ull, g_pHEX, FORMAT_NO_SIGN, FORMAT_NO_PREFIX); + } + else if (eTypeUintHex == l_pArg->eType) + { + l_uValue.uMax = 0ull; + COPY_ARG(l_uValue.uMax, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + if (l_pArg->bFlagGrid) {l_iWidth -=2;} //0x + FORMAT_DIGIT(16ull, g_pHex, FORMAT_NO_SIGN, FORMAT_X_PREFIX); + } + else if (eTypeUintHEX == l_pArg->eType) + { + l_uValue.uMax = 0ull; + COPY_ARG(l_uValue.uMax, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + if (l_pArg->bFlagGrid) {l_iWidth -=2;} //0x + FORMAT_DIGIT(16ull, g_pHEX, FORMAT_NO_SIGN, FORMAT_X_PREFIX); + + //Code snippet for test + //l_pDigit = m_pBuffer->pBuffer + m_pBuffer->szBuffer - 1; + //l_pTail = l_pDigit; + //*l_pDigit = TM('0'); + // + //if (l_uValue.uMax) l_pDigit++; + //while(l_uValue.uMax) + //{ + // *(--l_pDigit) =*(g_pHEX + (size_t)(l_uValue.uMax % 16)); + // l_uValue.uMax /= 16; + //} + // + //l_szAdd = (size_t)(l_pTail - l_pDigit + 1); + //l_iPrecision -= (tINT32)l_szAdd; + //l_iWidth -= (tINT32)l_szAdd; + //if (0 < l_iPrecision) l_iWidth -= l_iPrecision; + // + //if (0 < l_iWidth) l_szAdd += l_iWidth; + //if (0 < l_iPrecision) l_szAdd += l_iPrecision; + // + //if ((l_szReturn + l_szAdd + 1) >= i_szBuffer) + //{ + // l_bError = TRUE; + // break; + //} + // + //l_pIter = o_pBuffer + l_szReturn; + // + //if (FALSE == l_pArg->bFlagLeftAlign) + //{ + // if (TM(' ') == l_pArg->cPadding) + // { + // while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; + // } + // + // //if (l_bMinus) {*l_pIter++ = TM('-'); l_iWidth --;} + // //else if (l_pArg->bFlagSign) {*l_pIter++ = TM('+'); l_iWidth --;} + // if (l_pArg->bFlagGrid) {*l_pIter++ = TM('0'); *l_pIter++ = TM('x');} + // + // if (TM('0') == l_pArg->cPadding) + // { + // while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; + // } + // while (0 < l_iPrecision--) *l_pIter++ = TM('0'); + // + // l_szAdd = (size_t)(l_pTail - l_pDigit + 1); + // memcpy(l_pIter, l_pDigit, sizeof(tXCHAR) * l_szAdd); + // l_pIter += l_szAdd; + //} + //else + //{ + // //if (l_bMinus) {*l_pIter++ = TM('-'); l_iWidth --;} + // //else if (l_pArg->bFlagSign) {*l_pIter++ = TM('+'); l_iWidth --;} + // if (l_pArg->bFlagGrid) {*l_pIter++ = TM('0'); *l_pIter++ = TM('x');} + // + // while (0 < l_iPrecision--) *l_pIter++ = TM('0'); + // + // if (TM('0') == l_pArg->cPadding) + // { + // while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; + // } + // + // l_szAdd = (size_t)(l_pTail - l_pDigit + 1); + // memcpy(l_pIter, l_pDigit, sizeof(tXCHAR) * l_szAdd); + // l_pIter += l_szAdd; + // + // if (TM(' ') == l_pArg->cPadding) + // { + // while (0 < l_iWidth--) *l_pIter++ = l_pArg->cPadding; + // } + //} + // + //l_szReturn = (size_t)(l_pIter - o_pBuffer); + } + else if (eTypeUintBin == l_pArg->eType) + { + l_uValue.uMax = 0ull; + COPY_ARG(l_uValue.uMax, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + if (l_pArg->bFlagGrid) {l_iWidth --;}//b + FORMAT_DIGIT(2ull, g_pHEX, FORMAT_NO_SIGN, FORMAT_B_PREFIX); + } + else if (eTypeString == l_pArg->eType) + { + tINT32 l_iReturn = -1; + if (P7TRACE_ARG_TYPE_USTR16 == l_pP7Args->bType) + { + #ifdef UTF8_ENCODING + l_iReturn = Convert_UTF16_To_UTF8((tWCHAR*)i_pValues, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + //move var_arg pointer + while (*(tWCHAR*)i_pValues) i_pValues += sizeof(tWCHAR); + i_pValues += sizeof(tWCHAR); + #else //UTF-16 + COPY_STR(tWCHAR, tWCHAR); + #endif + } + else if (P7TRACE_ARG_TYPE_STRA == l_pP7Args->bType) + { + COPY_STR(tACHAR, tXCHAR); + } + else if (P7TRACE_ARG_TYPE_USTR8 == l_pP7Args->bType) + { + #ifdef UTF8_ENCODING + COPY_STR(tACHAR, tXCHAR); + #else + l_iReturn = Convert_UTF8_To_UTF16((tACHAR*)i_pValues, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + //move var_arg pointer + while (*(tACHAR*)i_pValues) i_pValues += sizeof(tACHAR); + i_pValues += sizeof(tACHAR); + #endif + } + else if (P7TRACE_ARG_TYPE_USTR32 == l_pP7Args->bType) + { + #ifdef UTF8_ENCODING + l_iReturn = Convert_UTF32_To_UTF8((tUINT32*)i_pValues, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + #else + l_iReturn = Convert_UTF32_To_UTF16((tUINT32*)i_pValues, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + #endif + //move var_arg pointer + while (*(tUINT32*)i_pValues) i_pValues += sizeof(tUINT32); + i_pValues += sizeof(tUINT32); + } + + if ( (l_iReturn >= 0) && ((size_t)(l_iReturn + 8) < (i_szBuffer - l_szReturn)) ) + { l_szReturn += (size_t)l_iReturn; } + else { l_bError = TRUE; break; } + } + else if (eTypeChar == l_pArg->eType) + { + //7 bytes max for UTF-8 + zero + if ((i_szBuffer - l_szReturn) < 7) {l_bError = TRUE; break;} + + if (P7TRACE_ARG_TYPE_CHAR == l_pP7Args->bType) + { + tINT8 l_iVal = 0; + COPY_ARG(l_iVal, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + + *(o_pBuffer + l_szReturn++) = l_iVal; + } + else if (P7TRACE_ARG_TYPE_CHAR16 == l_pP7Args->bType) + { + tINT16 l_iVal = 0; + COPY_ARG(l_iVal, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + + #ifdef UTF8_ENCODING + tWCHAR l_pWstr[2] = {(tWCHAR)l_iVal, 0}; + l_szReturn += (size_t)Convert_UTF16_To_UTF8((tWCHAR*)l_pWstr, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + #else + *(o_pBuffer + l_szReturn++) = l_iVal; + #endif + } + else if (P7TRACE_ARG_TYPE_CHAR32 == l_pP7Args->bType) + { + tUINT32 l_pVal[2] = {0, 0}; + COPY_ARG(l_pVal[0], g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + #ifdef UTF8_ENCODING + l_szReturn += (size_t)Convert_UTF32_To_UTF8((tUINT32*)l_pVal, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + #else + l_szReturn += (size_t)Convert_UTF32_To_UTF16((tUINT32*)l_pVal, + o_pBuffer + l_szReturn, + (tUINT32)(i_szBuffer - l_szReturn) + ); + #endif + } + } + else if (eTypePointer == l_pArg->eType) + { + l_uValue.uMax = 0ull; + COPY_ARG(l_uValue.uMax, l_pP7Args->bSize, l_pP7Args->bSize); + l_iWidth -=2; //0x + FORMAT_DIGIT(16ull, g_pHEX, FORMAT_NO_SIGN, FORMAT_X_PREFIX); + } + else if (eTypeDouble == l_pArg->eType) + { + tINT32 l_iCount; + + memcpy(&l_uValue.d64, i_pValues, l_pP7Args->bSize); + + if ( (FORMATTER_ARG_WIDTH == l_pArg->iWidth) + && (FORMATTER_ARG_PRECISION == l_pArg->iPrecision) + ) + { + l_iCount = PSPrint(o_pBuffer + l_szReturn, + i_szBuffer - l_szReturn, + l_pArg->pDouble, + l_iWidth, + l_iPrecision, + l_uValue.d64 + ); + } + else if (FORMATTER_ARG_PRECISION == l_pArg->iPrecision) + { + l_iCount = PSPrint(o_pBuffer + l_szReturn, + i_szBuffer - l_szReturn, + l_pArg->pDouble, + l_iPrecision, + l_uValue.d64 + ); + } + else if (FORMATTER_ARG_WIDTH == l_pArg->iPrecision) + { + l_iCount = PSPrint(o_pBuffer + l_szReturn, + i_szBuffer - l_szReturn, + l_pArg->pDouble, + l_iWidth, + l_uValue.d64 + ); + } + else + { + l_iCount = PSPrint(o_pBuffer + l_szReturn, + i_szBuffer - l_szReturn, + l_pArg->pDouble, + l_uValue.d64 + ); + } + + if (0 < l_iCount) + { + l_szReturn += (size_t)l_iCount; + } + else + { + l_bError = TRUE; + break; + } + } + else if (eTypeUintOct == l_pArg->eType) + { + l_uValue.uMax = 0ull; + COPY_ARG(l_uValue.uMax, g_pSize[l_pP7Args->bType], l_pP7Args->bSize); + if (l_pArg->bFlagGrid) {l_iWidth --;}//0 + FORMAT_DIGIT(8ull, g_pHEX, FORMAT_NO_SIGN, FORMAT_0_PREFIX); + } + + l_pArg = l_pArg->pNext; + i_pValues += l_pP7Args->bSize; //for strings it is 0 + l_pP7Args ++; + } //while(l_pArg) + + if (l_szReturn < i_szBuffer) + { + o_pBuffer[l_szReturn] = 0; + } + + return (!l_bError) ? (tINT32)l_szReturn : -1; + }//Format + + //////////////////////////////////////////////////////////////////////////// + //Print - test function, print format string back to buffer + // tBOOL Print(tXCHAR *o_pBuffer, size_t i_szBuffer) + // { + // size_t l_szOffs = 0; + // sArg *l_pArg = m_pArgHead; + // tBOOL l_bReturn = TRUE; + // size_t l_szDouble = 0; + // + // while (l_pArg) + // { + // l_szDouble = (l_pArg->pDouble) ? PStrLen(l_pArg->pDouble) : 0; + // + // if ((i_szBuffer - l_szOffs) < (l_pArg->szPrefix + l_szDouble + 64)) + // { + // l_bReturn = FALSE; + // break; + // } + // + // if (l_pArg->pPrefix) + // { + // memcpy(o_pBuffer + l_szOffs, l_pArg->pPrefix, l_pArg->szPrefix * sizeof(tXCHAR)); + // l_szOffs += l_pArg->szPrefix; + // } + // + // if (eTypeDouble == l_pArg->eType) + // { + // if (l_szDouble) + // { + // PStrCpy(o_pBuffer + l_szOffs, i_szBuffer-l_szOffs, l_pArg->pDouble); + // l_szOffs += l_szDouble; + // } + // else + // { + // l_bReturn = FALSE; + // break; + // } + // } + // else if (eTypeNone != l_pArg->eType) + // { + // o_pBuffer[l_szOffs++] = TM('%'); + // + // if (l_pArg->bFlagSign) { o_pBuffer[l_szOffs++] = TM('+'); } + // if (l_pArg->bFlagLeftAlign) { o_pBuffer[l_szOffs++] = TM('-'); } + // if (l_pArg->bFlagBlankPrefix) { o_pBuffer[l_szOffs++] = TM(' '); } + // if (l_pArg->bFlagGrid) { o_pBuffer[l_szOffs++] = TM('#'); } + // if (l_pArg->bFlagZeroPrefix) { o_pBuffer[l_szOffs++] = TM('0'); } + // + // if (FORMATTER_NO_WIDTH == l_pArg->iWidth) {} + // else if (FORMATTER_ARG_WIDTH == l_pArg->iWidth) { o_pBuffer[l_szOffs++] = TM('*'); } + // else { l_szOffs += PSPrint(o_pBuffer + l_szOffs, i_szBuffer-l_szOffs, TM("%d"), l_pArg->iWidth);} + // + // if (FORMATTER_NO_PRECISION == l_pArg->iPrecision) + // { + // } + // else + // { + // o_pBuffer[l_szOffs++] = TM('.'); + // if (FORMATTER_ARG_PRECISION == l_pArg->iPrecision) { o_pBuffer[l_szOffs++] = TM('*'); } + // else if (FORMATTER_SKIP_PRECISION == l_pArg->iPrecision) { o_pBuffer[l_szOffs++] = TM('0'); } + // else { l_szOffs += PSPrint(o_pBuffer + l_szOffs, i_szBuffer-l_szOffs, TM("%d"), l_pArg->iPrecision);} + // } + // + // if (eSizehh == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('h'); + // o_pBuffer[l_szOffs++] = TM('h'); + // } + // else if (eSizell == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('l'); + // o_pBuffer[l_szOffs++] = TM('l'); + // } + // else if (eSizeh == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('h'); + // } + // else if (eSizel == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('l'); + // } + // else if (eSizeI == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('I'); + // } + // else if (eSizez == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('z'); + // } + // else if (eSize32 == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('I'); + // o_pBuffer[l_szOffs++] = TM('3'); + // o_pBuffer[l_szOffs++] = TM('2'); + // } + // else if (eSize64 == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('I'); + // o_pBuffer[l_szOffs++] = TM('6'); + // o_pBuffer[l_szOffs++] = TM('4'); + // } + // else if (eSizet == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('t'); + // } + // else if (eSizeL == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('L'); + // } + // else if (eSizew == l_pArg->eSize) + // { + // o_pBuffer[l_szOffs++] = TM('w'); + // } + // + // if (eTypeStringH == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('s');} + // else if (eTypeStringW == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('S');} + // else if (eTypeInt_d == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('d');} + // else if (eTypeInt_u == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('u');} + // else if (eTypeInt_i == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('i');} + // else if (eTypeInt_x == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('x');} + // else if (eTypeInt_X == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('X');} + // else if (eTypeInt_o == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('o');} + // else if (eTypeInt_b == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('b');} + // else if (eTypeInt_p == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('p');} + // else if (eTypeInt_n == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('n');} + // else if (eTypeInt_c == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('c');} + // else if (eTypeInt_C == l_pArg->eType) {o_pBuffer[l_szOffs++] = TM('C');} + // } + // + // l_pArg = l_pArg->pNext; + // } + // + // if (l_bReturn) + // { + // o_pBuffer[l_szOffs] = 0; + // } + // + // return l_bReturn; + // } + + //////////////////////////////////////////////////////////////////////////// + //TestScan - test function + /* + static tBOOL TestScan() + { + tXCHAR l_pBuffer[8192]; + CFormatter *l_pFormatter = NULL; + const tXCHAR *l_pPattern = NULL; + const tXCHAR *l_pError = NULL; + + #define COMPARE_PATTERN(i_pFormat, i_pPattern)\ + if (l_pFormatter)\ + {\ + delete l_pFormatter;\ + }\ + l_pFormatter = new CFormatter(TM(i_pFormat), NULL, 0, NULL);\ + l_pPattern = TM(i_pPattern);\ + if ( (!l_pFormatter->Print(l_pBuffer, 8192))\ + || (0 != PStrCmp(l_pBuffer, l_pPattern))\ + )\ + {\ + l_pError = l_pPattern;\ + goto l_blExit;\ + }\ + + COMPARE_PATTERN("%%1 %I32d %%2 %I64d %%3 %hhd %%4 %wd %%5 %Ld %%6 %lld %%7 %ld %%8 %Id %%9 %zd %%10 %td", + "%1 %I32d %2 %I64d %3 %hhd %4 %wd %5 %Ld %6 %lld %7 %ld %8 %Id %9 %zd %10 %td" + ); + COMPARE_PATTERN("%+- #0*lld", "%+- #0*lld"); + COMPARE_PATTERN("%+- #0123lld", "%+- #0123lld"); + COMPARE_PATTERN("%+.03f", "%+.03f"); + COMPARE_PATTERN("%.0d", "%.0d"); + COMPARE_PATTERN("Test1 %.*d Test2 %.*d", "Test1 %.*d Test2 %.*d"); + COMPARE_PATTERN("%s%S%d%u%i%x%X%o%c%C%b%p%n", "%s%S%d%u%i%x%X%o%c%C%b%p%n"); + COMPARE_PATTERN("Test %hc", "Test %hc"); + COMPARE_PATTERN("Test %wc", "Test %wc"); + COMPARE_PATTERN("Test %lc", "Test %lc"); + COMPARE_PATTERN("Test %0c", "Test %0c"); + COMPARE_PATTERN("Test %%", "Test %"); + COMPARE_PATTERN("%% Test", "% Test"); + COMPARE_PATTERN("%%%c Test", "%%c Test"); + COMPARE_PATTERN("%% Test", "% Test"); + COMPARE_PATTERN("Test %%", "Test %"); + COMPARE_PATTERN("Test %c Test", "Test %c Test"); + + l_blExit: + delete l_pFormatter; + + if (l_pError) + { + printf("ERROR"); + } + + return l_pError ? FALSE : TRUE; + } + */ + +private: + //////////////////////////////////////////////////////////////////////////// + //AddArg + sArg *AddArg(const tXCHAR *i_pPrefix, size_t i_szPrefix) + { + sArg *l_pReturn = new sArg(); + if (l_pReturn) + { + if (i_szPrefix) + { + l_pReturn->pPrefix = (tXCHAR*)malloc(i_szPrefix * sizeof(tXCHAR)); + if (l_pReturn->pPrefix) + { + const tXCHAR *l_pSrc = i_pPrefix; + tXCHAR *l_pDst = l_pReturn->pPrefix; + + l_pReturn->szPrefix = 0; + + while (i_szPrefix--) + { + *l_pDst = *l_pSrc; + l_pDst ++; + l_pReturn->szPrefix++; + + if ( (TM('%') == *l_pSrc) + && (TM('%') == *(l_pSrc + 1)) + ) + { + l_pSrc ++; + i_szPrefix--; + } + + l_pSrc ++; + } + } + } + } + return l_pReturn; + } + + //////////////////////////////////////////////////////////////////////////// + //GetSize + CFormatter::eSize GetSize(const tXCHAR *&i_pFormat) + { + struct sSize{ const tXCHAR *pPrefix; size_t szPrefix; CFormatter::eSize eSize;}; + const static sSize g_pSize[] = {{TM("I64"), 3, eSize64}, + {TM("I32"), 3, eSize32}, + {TM("ll"), 2, eSizell}, + {TM("hh"), 2, eSizehh}, + {TM("h"), 1, eSizeh }, + {TM("w"), 1, eSizew }, + {TM("l"), 1, eSizel }, + {TM("L"), 1, eSizeL }, + {TM("I"), 1, eSizeI }, + {TM("z"), 1, eSizez }, + {TM("j"), 1, eSizej }, + {TM("t"), 1, eSizet }, + {TM("?"), 0, eSize32} + }; + + const sSize *l_pIter = &g_pSize[0]; + + while (l_pIter->szPrefix) + { + if (0 == PStrNCmp(i_pFormat, l_pIter->pPrefix, l_pIter->szPrefix)) + { + i_pFormat += l_pIter->szPrefix; + return l_pIter->eSize; + } + + l_pIter ++; + } + + return eSizeUnk; + } +}; + +#endif //FORMATTER_H \ No newline at end of file diff --git a/p7lib/Sources/PacketsPool.h b/p7lib/Sources/PacketsPool.h new file mode 100644 index 0000000..9a62550 --- /dev/null +++ b/p7lib/Sources/PacketsPool.h @@ -0,0 +1,386 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file describe buffers pool / +//////////////////////////////////////////////////////////////////////////////// +#ifndef PACKETSPOOL_H +#define PACKETSPOOL_H + +#include + +//////////////////////////////////////////////////////////////////////////////// +//CBuffers_Pool +class CBuffers_Pool +{ +protected: + struct sChunk + { + tUINT8 *pData; + sChunk *pNext; + + sChunk() + { + pData = NULL; + pNext = NULL; + } + }; + + //put volatile variables at the top, to obtain 32 bit alignment. + //Project has 8 tUINT8s alignment by default + volatile tINT32 m_lReference_Count; + volatile tUINT32 m_dwSize; + volatile tUINT32 *m_pSize; + tUINT32 m_dwMax_Size; + tUINT32 m_dwChunk_Size; + tUINT32 m_dwPacket_Size; + + CBList m_cBuffers; + tUINT32 m_dwCount; + tUINT32 m_dwMax_Count; + tUINT32 m_dwExtracted; + + tUINT32 m_dwBuffer_Size; + tLOCK m_hCS; + IJournal *m_pLog; + tUINT32 m_dwID; + tBOOL m_bInitialized; + + sChunk *m_pChunk_First; +public: + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::CBuffers_Pool + CBuffers_Pool(IJournal *i_pLog, + tUINT32 i_dwChunk_Size, + tUINT32 i_dwMax_Size, + tUINT32 i_dwBuffer_Size, + tUINT32 i_dwID + ) + : m_lReference_Count(0) + , m_dwSize(0) + , m_pSize(&m_dwSize) + , m_dwMax_Size(i_dwMax_Size) + , m_dwChunk_Size(i_dwChunk_Size) + , m_dwPacket_Size(0) + + , m_dwCount(0) + , m_dwMax_Count(0) + , m_dwExtracted(0) + , m_dwBuffer_Size(i_dwBuffer_Size) + , m_pLog(i_pLog) + , m_dwID(i_dwID) + , m_bInitialized(TRUE) + , m_pChunk_First(NULL) + { + if (m_pLog) + { + m_pLog->Add_Ref(); + } + + LOCK_CREATE(m_hCS); + + m_dwPacket_Size = sizeof(CTPacket) + i_dwBuffer_Size; + m_dwChunk_Size = ((m_dwChunk_Size / m_dwPacket_Size) + 1) * m_dwPacket_Size; + m_dwMax_Count = i_dwMax_Size / m_dwPacket_Size; + //m_bInitialized = Allocate(m_dwChunk_Size); + }//CBuffers_Pool::CBuffers_Pool + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::~CBuffers_Pool + ~CBuffers_Pool() + { + if (m_dwExtracted) + { + JOURNAL_ERROR(m_pLog, + TM("%d buffers are missed !."), + (tUINT32)m_dwExtracted + ); + } + + if (0 < Get_Reference_Count()) + { + JOURNAL_ERROR(m_pLog, TM("Reference count is greater than 0 !")); + } + + m_cBuffers.Clear(FALSE); + + sChunk *l_pNext = NULL; + while (m_pChunk_First) + { + l_pNext = m_pChunk_First->pNext; + + if (m_pChunk_First->pData) + { + delete [] m_pChunk_First->pData; + } + + delete m_pChunk_First; + + m_pChunk_First = l_pNext; + } + + if (m_pLog) + { + m_pLog->Release(); + m_pLog = NULL; + } + + LOCK_DESTROY(m_hCS); + }//CBuffers_Pool::~CBuffers_Pool + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Allocate + tBOOL Allocate(tUINT32 i_dwSize) + { + CTPacket *l_pPacket = NULL; + sChunk *l_pChunk = NULL; + tUINT8 *l_pData = NULL; + + if ((*m_pSize) >= m_dwMax_Size) + { + JOURNAL_ERROR(m_pLog, + TM("Failed, Memory limit is reached, ID = %d Count = %d, Max = %d. Buffer Size = %d, Memory limit = %d"), + (tUINT32)m_dwID, + (tUINT32)m_dwCount, + (tUINT32)m_dwMax_Count, + (tUINT32)m_dwBuffer_Size, + (tUINT32)m_dwMax_Size + ); + + return FALSE; + } + + if (NULL == (l_pChunk = new sChunk())) + { + JOURNAL_ERROR(m_pLog, TM("Buffer allocation failed.")); + return FALSE; + } + + l_pChunk->pData = new tUINT8[i_dwSize]; + if (NULL == l_pChunk->pData) + { + JOURNAL_ERROR(m_pLog, TM("Buffer allocation failed.")); + delete l_pChunk; + return FALSE; + } + + LOCK_ENTER(m_hCS); + + l_pChunk->pNext = m_pChunk_First; + m_pChunk_First = l_pChunk; + l_pData = l_pChunk->pData; + + ATOMIC_ADD((volatile tINT32*)m_pSize, i_dwSize); + + for (tUINT32 l_dwI = 0; l_dwI < (i_dwSize / m_dwPacket_Size); l_dwI++) + { + l_pPacket = new (l_pData) CTPacket(l_pData + sizeof(CTPacket), + m_dwBuffer_Size, + m_dwID + ); + l_pData += m_dwPacket_Size; + m_cBuffers.Add_After(m_cBuffers.Get_Last(), l_pPacket); + m_dwCount ++; + } + + LOCK_EXIT(m_hCS); + + return TRUE; + }//CBuffers_Pool::Allocate + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Get_Initialized + tBOOL Get_Initialized() + { + return m_bInitialized; + }//CBuffers_Pool::Get_Initialized + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Get_Buffer_Size + tUINT32 Get_Buffer_Size() + { + return m_dwBuffer_Size; + }//CBuffers_Pool::Get_Buffer_Size + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Get_Max_Size + tUINT32 Get_Max_Size() + { + return m_dwMax_Size; + } + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Get_Free_Count + tUINT32 Get_Free_Count() + { + tUINT32 l_dwReturn = 0; + + LOCK_ENTER(m_hCS); + + l_dwReturn = m_dwMax_Count - m_dwExtracted; + + LOCK_EXIT(m_hCS); + + return l_dwReturn; + }//CBuffers_Pool::Get_Free_Count + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Get_Memory_Info + void Get_Memory_Info(tUINT32 *o_dwUsed, + tUINT32 *o_dwFree, + tUINT32 *o_pAllocated + ) + { + LOCK_ENTER(m_hCS); + + if (o_dwUsed) + { + *o_dwUsed = m_dwExtracted * m_dwBuffer_Size; + } + + if (o_dwFree) + { + *o_dwFree = (m_dwMax_Count - m_dwExtracted) * m_dwBuffer_Size; + } + + if (o_pAllocated) + { + *o_pAllocated = *m_pSize; + } + + LOCK_EXIT(m_hCS); + }//CBuffers_Pool::Get_Memory_Info + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Pull_Buffer + CTPacket *Pull_Buffer() + { + CTPacket *l_pReturn = NULL; + pAList_Cell l_pCell = NULL; + + LOCK_ENTER(m_hCS); + + if (0 >= m_cBuffers.Count()) + { + Allocate(m_dwChunk_Size); + } + + l_pCell = m_cBuffers.Get_First(); + + if (l_pCell) + { + l_pReturn = m_cBuffers.Get_Data(l_pCell); + m_cBuffers.Del(l_pCell, FALSE); + m_dwExtracted ++; + } + + LOCK_EXIT(m_hCS); + return l_pReturn; + }//CBuffers_Pool::Pull_Buffer + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Push_Buffer + void Push_Buffer(CTPacket *i_pBuffer) + { + if ( (NULL == i_pBuffer) + || (0 == m_dwExtracted) + ) + { + JOURNAL_ERROR(m_pLog, TM("Wrong parameters.")); + return; + } + + + LOCK_ENTER(m_hCS); + + m_cBuffers.Add_After(m_cBuffers.Get_Last(), i_pBuffer); + m_dwExtracted --; + + LOCK_EXIT(m_hCS); + }//CBuffers_Pool::Push_Buffer + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Inc_Reference_Count + tINT32 Inc_Reference_Count() + { + tINT32 l_lReturn = 0; + + LOCK_ENTER(m_hCS); + + m_lReference_Count ++; + l_lReturn = m_lReference_Count; + + LOCK_EXIT(m_hCS); + + return l_lReturn; + }//CBuffers_Pool::Inc_Reference_Count + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Dec_Reference_Count + tINT32 Dec_Reference_Count() + { + tINT32 l_lReturn = 0; + + LOCK_ENTER(m_hCS); + + m_lReference_Count --; + l_lReturn = m_lReference_Count; + + LOCK_EXIT(m_hCS); + + return l_lReturn; + }//CBuffers_Pool::Dec_Reference_Count + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Get_Reference_Count + tINT32 Get_Reference_Count() + { + tINT32 l_lReturn = 0; + + LOCK_ENTER(m_hCS); + + l_lReturn = m_lReference_Count; + + LOCK_EXIT(m_hCS); + + return l_lReturn; + }//CBuffers_Pool::Get_Reference_Count + + + //////////////////////////////////////////////////////////////////////////// + //CBuffers_Pool::Set_External_Size + void Set_External_Size(volatile tUINT32 *i_pSize) + { + LOCK_ENTER(m_hCS); + m_pSize = i_pSize; + LOCK_EXIT(m_hCS); + }//CBuffers_Pool::Set_External_Size +}; + +#endif //PACKETSPOOL_H diff --git a/p7lib/Sources/Proxy.cpp b/p7lib/Sources/Proxy.cpp new file mode 100644 index 0000000..243d15a --- /dev/null +++ b/p7lib/Sources/Proxy.cpp @@ -0,0 +1,521 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file provide functionality to deliver data to NULL / +//////////////////////////////////////////////////////////////////////////////// + +#include "CommonClient.h" +#include "P7_Cproxy.h" + +extern "C" +{ +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7 client // +// // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Create +P7_EXPORT hP7_Client __cdecl P7_Client_Create(const tXCHAR *i_pName) +{ + return P7_Create_Client(i_pName); +}//P7_Client_Create + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Get_Shared +P7_EXPORT hP7_Client __cdecl P7_Client_Get_Shared(const tXCHAR *i_pName) +{ + return P7_Get_Shared(i_pName); +}//P7_Client_Get_Shared + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Share +P7_EXPORT tBOOL __cdecl P7_Client_Share(hP7_Client i_hClient, const tXCHAR *i_pName) +{ + IP7_Client *l_pClient = static_cast(i_hClient); + + if (!l_pClient) + { + return FALSE; + } + + return l_pClient->Share(i_pName); +}//P7_Client_Share + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Flush +P7_EXPORT void __cdecl P7_Client_Flush(hP7_Client i_hClient) +{ + IP7_Client *l_pClient = static_cast(i_hClient); + + if (!l_pClient) + { + return; + } + + l_pClient->Flush(); +}//P7_Client_Flush + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Add_Ref +P7_EXPORT tINT32 __cdecl P7_Client_Add_Ref(hP7_Client i_hClient) +{ + IP7_Client *l_pClient = static_cast(i_hClient); + + if (!l_pClient) + { + return -1; + } + + return l_pClient->Add_Ref(); +}//P7_Client_Add_Ref + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Client_Release +P7_EXPORT tINT32 __cdecl P7_Client_Release(hP7_Client i_hClient) +{ + IP7_Client *l_pClient = static_cast(i_hClient); + + if (!l_pClient) + { + return -1; + } + + return l_pClient->Release(); +}//P7_Client_Release + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7 Telemetry // +// // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Create +P7_EXPORT hP7_Telemetry __cdecl P7_Telemetry_Create(hP7_Client i_hClient, + const tXCHAR *i_pName, + const stTelemetry_Conf *i_pConf + ) +{ + return P7_Create_Telemetry(static_cast(i_hClient), i_pName, i_pConf); +}//P7_Telemetry_Create + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Share +P7_EXPORT tBOOL __cdecl P7_Telemetry_Share(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName + ) +{ + IP7_Telemetry *l_pTel = static_cast(i_hTelemetry); + if (NULL == l_pTel) + { + return FALSE; + } + + return l_pTel->Share(i_pName); +}//P7_Telemetry_Share + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Get_Shared +P7_EXPORT hP7_Telemetry __cdecl P7_Telemetry_Get_Shared(const tXCHAR *i_pName) +{ + return P7_Get_Shared_Telemetry(i_pName); +}//P7_Telemetry_Get_Shared + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Create_Counter +P7_EXPORT tBOOL __cdecl P7_Telemetry_Create_Counter(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + tBOOL i_bOn, + tUINT16 *o_pID + ) +{ + IP7_Telemetry *l_pTel = static_cast(i_hTelemetry); + if (NULL == l_pTel) + { + return FALSE; + } + + return l_pTel->Create(i_pName, + i_dbMin, + i_dbAlarmMin, + i_dbMax, + i_dbAlarmMax, + i_bOn, + o_pID + ); +}//P7_Telemetry_Create_Counter + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Put_Value +P7_EXPORT tBOOL __cdecl P7_Telemetry_Put_Value(hP7_Telemetry i_hTelemetry, + tUINT16 i_wCounter_ID, + tDOUBLE i_dbValue) +{ + IP7_Telemetry *l_pTel = static_cast(i_hTelemetry); + if (NULL == l_pTel) + { + return FALSE; + } + + return l_pTel->Add(i_wCounter_ID, i_dbValue); +}//P7_Telemetry_Put_Value + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Find_Counter +P7_EXPORT tBOOL __cdecl P7_Telemetry_Find_Counter(hP7_Telemetry i_hTelemetry, + const tXCHAR *i_pName, + tUINT16 *o_pCounter_ID + ) +{ + IP7_Telemetry *l_pTel = static_cast(i_hTelemetry); + if (NULL == l_pTel) + { + return FALSE; + } + + return l_pTel->Find(i_pName, o_pCounter_ID); +}//P7_Telemetry_Find_Counter + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Add_Ref +P7_EXPORT tINT32 __cdecl P7_Telemetry_Add_Ref(hP7_Telemetry i_hTelemetry) +{ + IP7_Telemetry *l_pTel = static_cast(i_hTelemetry); + if (NULL == l_pTel) + { + return -1; + } + + return l_pTel->Add_Ref(); +}//P7_Telemetry_Add_Ref + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Telemetry_Release +P7_EXPORT tINT32 __cdecl P7_Telemetry_Release(hP7_Telemetry i_hTelemetry) +{ + IP7_Telemetry *l_pTel = static_cast(i_hTelemetry); + if (NULL == l_pTel) + { + return -1; + } + + return l_pTel->Release(); +}//P7_Telemetry_Release + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// // +// P7 Trace // +// // +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Create_Trace +P7_EXPORT hP7_Trace __cdecl P7_Trace_Create(hP7_Client i_hClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf + ) +{ + return P7_Create_Trace(static_cast(i_hClient), i_pName, i_pConf); +}//P7_Trace_Create_Trace + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Get_Shared +P7_EXPORT hP7_Trace __cdecl P7_Trace_Get_Shared(const tXCHAR *i_pName) +{ + return P7_Get_Shared_Trace(i_pName); +}//P7_Trace_Get_Shared + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Share +P7_EXPORT tBOOL __cdecl P7_Trace_Share(hP7_Trace i_hTrace, + const tXCHAR *i_pName + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return FALSE; + } + + return l_pTrace->Share(i_pName); +}//P7_Trace_Share + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Set_Verbosity +P7_EXPORT void __cdecl P7_Trace_Set_Verbosity(hP7_Trace i_hTrace, + hP7_Trace_Module i_hModule, + tUINT32 i_dwLevel + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return; + } + + l_pTrace->Set_Verbosity(i_hModule, (eP7Trace_Level)i_dwLevel); +}//P7_Trace_Set_Verbosity + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Set_Verbosity +P7_EXPORT tUINT32 __cdecl P7_Trace_Get_Verbosity(hP7_Trace i_hTrace, + hP7_Trace_Module i_hModule + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return EP7TRACE_LEVEL_COUNT; + } + + return l_pTrace->Get_Verbosity(i_hModule); +}//P7_Trace_Set_Verbosity + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Register_Thread +P7_EXPORT tBOOL __cdecl P7_Trace_Register_Thread(hP7_Trace i_hTrace, + const tXCHAR *i_pName, + tUINT32 i_dwThreadId + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return FALSE; + } + + return l_pTrace->Register_Thread(i_pName, i_dwThreadId); +}//P7_Trace_Register_Thread + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Unregister_Thread +P7_EXPORT tBOOL __cdecl P7_Trace_Unregister_Thread(hP7_Trace i_hTrace, + tUINT32 i_dwThreadId + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return FALSE; + } + + return l_pTrace->Unregister_Thread(i_dwThreadId); +}//P7_Trace_Unregister_Thread + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Register_Module +P7_EXPORT hP7_Trace_Module __cdecl P7_Trace_Register_Module(hP7_Trace i_hTrace, + const tXCHAR *i_pName + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + hP7_Trace_Module l_hMpodule = NULL; + + if (NULL == l_pTrace) + { + return NULL; + } + + if (l_pTrace->Register_Module(i_pName, &l_hMpodule)) + { + return l_hMpodule; + } + + return NULL; +}//P7_Trace_Register_Module + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Add +P7_EXPORT tBOOL __cdecl P7_Trace_Add(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR *i_pFormat, + ... + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return FALSE; + } + +#if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + va_list l_pVl; + va_start(l_pVl, i_pFormat); + tBOOL l_bRet = l_pTrace->Trace_Embedded(i_wTrace_ID, + (eP7Trace_Level)i_dwLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + &i_pFormat, + &l_pVl + ); + va_end(l_pVl); + return l_bRet; +#else + return l_pTrace->Trace_Embedded(i_wTrace_ID, + (eP7Trace_Level)i_dwLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + &i_pFormat + ); +#endif +}//P7_Trace_Add + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Embedded +P7_EXPORT tBOOL __cdecl P7_Trace_Embedded(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return FALSE; + } + + return l_pTrace->Trace_Embedded(i_wTrace_ID, + (eP7Trace_Level)i_dwLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + i_ppFormat, + i_pVa_List + ); +}//P7_Trace_Embedded + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Managed +P7_EXPORT extern tBOOL __cdecl P7_Trace_Managed(hP7_Trace i_hTrace, + tUINT16 i_wTrace_ID, + tUINT32 i_dwLevel, + hP7_Trace_Module i_hModule, + tUINT16 i_wLine, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + const tXCHAR *i_pMessage + ) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return FALSE; + } + + return l_pTrace->Trace_Managed(i_wTrace_ID, + (eP7Trace_Level)i_dwLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + i_pMessage + ); +}//P7_Trace_Managed + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Add_Ref +P7_EXPORT tINT32 __cdecl P7_Trace_Add_Ref(hP7_Trace i_hTrace) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return -1; + } + + return l_pTrace->Add_Ref(); +}//P7_Trace_Add_Ref + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Trace_Release +P7_EXPORT tINT32 __cdecl P7_Trace_Release(hP7_Trace i_hTrace) +{ + IP7_Trace *l_pTrace = static_cast(i_hTrace); + if (NULL == l_pTrace) + { + return -1; + } + + return l_pTrace->Release(); +}//P7_Trace_Release + + +} //extern "C" + diff --git a/p7lib/Sources/TPackets.h b/p7lib/Sources/TPackets.h new file mode 100644 index 0000000..3a4afde --- /dev/null +++ b/p7lib/Sources/TPackets.h @@ -0,0 +1,1489 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This header file describe all packets types which are used in communication / +// N.B.: In this file I remove all checks for valid pointers and packets / +// because this job is made outside by packet pool. / +//////////////////////////////////////////////////////////////////////////////// +#ifndef TPACKETS_H +#define TPACKETS_H + +#define CLIENT_PROTOCOL_VERSION (0x0007) + +//this value can store 32 bits but to avoid overflow we reduce it +#define TPACKET_MAX_ID (0xFFFFFFF) +#define TPACKET_PROCESS_NAME_MAX_LEN (96) + + +//////////////////////////////////////////////////////////////////////////////// +//Transport Packet types, we have only 4 bits for them (16 types max) +enum eTPacket_Type +{ + ETPT_CLIENT_HELLO = 0x0, //tH_Common + tH_Client_Initial + ETPT_CLIENT_PING = 0x1, //tH_Common + ETPT_CLIENT_DATA = 0x2, + ETPT_CLIENT_DATA_REPORT = 0x3, + ETPT_CLIENT_BYE = 0x4, + + ETPT_ACKNOWLEDGMENT = 0x9, + ETPT_SERVER_DATA_REPORT = 0xA, + ETPT_SERVER_CHAINED = 0xB, + + ETPACKET_TYPE_UNASSIGNED = 0xF +}; + +enum eTPacket_Endian +{ + ETP_LITTLE_ENDIAN = 0, + ETP_BIG_ENDIAN , + ETP_MAX_ENDIAN +}; + +//////////////////////////////////////////////////////////////////////////////// +//Transport Packet extension types +enum eTPacket_Extension +{ + ETPE_SERVER_NETWORK_INFO = 0x0, //sH_Ext + sH_Ext_Srv_Info + ETPE_USER_DATA = 0x1, //sH_Ext + sH_User_Data + + ETPE_MAX = 0xFFFF +}; + + +#define TPACKET_MIN_SIZE (0x200) +#define TPACKET_DEF_SIZE (1472u) +#define TPACKET_MAX_SIZE (0xFF00) + +//////////////////////////////////////////////////////////////////////////////// +//Transport Packet flags +#define TPACKET_FLAG_EXTRA_DATA (0x001u) // 1 << 0 +#define TPACKET_FLAG_ARCH_64 (0x002u) // 1 << 1 +#define TPACKET_FLAG_EXTENSION (0x004u) // 1 << 2 +#define TPACKET_FLAG_BIG_ENDIAN_SRV (0x008u) // 1 << 3 +#define TPACKET_FLAG_RESERVED_04 (0x010u) // 1 << 4 +#define TPACKET_FLAG_RESERVED_05 (0x020u) // 1 << 5 +#define TPACKET_FLAG_RESERVED_06 (0x040u) // 1 << 6 +#define TPACKET_FLAG_RESERVED_07 (0x080u) // 1 << 7 +#define TPACKET_FLAG_RESERVED_08 (0x100u) // 1 << 8 +#define TPACKET_FLAG_RESERVED_09 (0x200u) // 1 << 9 +#define TPACKET_FLAG_RESERVED_10 (0x400u) // 1 << 10 +#define TPACKET_FLAG_BIG_ENDIAN_CLN (0x800u) // 1 << 11 + +#define TPACKET_TYPE_MASK (0xFu) +#define TPACKET_FLAGS_MASK (0xFFF0u) +#define TPACKET_FLAGS_OFFSET (4u) + + +//////////////////////////////////////////////////////////////////////////////// +//Transport Packet structures + + +PRAGMA_PACK_ENTER(2) //alignment is now 2, MS only ! + +//This is common header for every P7 transport packet, it situated at the +//beginning of the packet, then, depending on Type can be located other headers +struct sH_Common +{ + tUINT32 dwCRC32; + tUINT32 dwID; + tUINT16 wBits; //[0..3] - Type, [4..15] - flags + //tUINT16 wType:4; + //tUINT16 wFlags:12; + //We are working through UDP, so the packet size is limited to 65k. + //The minimum guaranteed size of the packet 576 bytes, user size is 512 bytes. + tUINT16 wSize; + tUINT16 wClient_ID; +} ATTR_PACK(2); + +struct sH_Client_Hello +{ + tUINT16 wProtocol_Version; + tUINT16 wData_Max_Size; + //Process ID and process time are dedicated to matching processes on server + //side + tUINT32 dwProcess_ID; + tUINT32 dwProcess_Start_Time_Hi; + tUINT32 dwProcess_Start_Time_Lo; + tWCHAR pProcess_Name[TPACKET_PROCESS_NAME_MAX_LEN]; +} ATTR_PACK(2); + + +struct sH_Data_Window +{ + tUINT32 dwFirst_ID; + tUINT32 dwLast_ID; +} ATTR_PACK(2); + + +struct sH_Packet_Ack +{ + tUINT32 dwSource_ID; + tUINT16 wResult; // 0 - NOK, 1 - OK +} ATTR_PACK(2); + + +struct sH_Ext +{ + tUINT16 wType; //extension type + tUINT16 wSize; //extension size +} ATTR_PACK(2); + + +struct sH_Ext_Srv_Info +{ + tUINT32 dwServerVersion; //Server version + tUINT16 wProtocolVersion;//Server protocol version + tUINT16 wMTU; //maximum transfer unit (max packet size passed by all network route devices), 0 if unknown + tUINT32 dwSocket_Buffer; //size of recv socket buffer in bytes +} ATTR_PACK(2); + + +struct sH_Data_Window_Report +{ + tUINT32 dwSource_ID; + tUINT8 pID[1]; //Array of the ID, each byte contains 8 ID markers ... bitfield +} ATTR_PACK(2); + + +//////////////////////////////////////////////////////////////////////////////// +// // +// User packet definitions // +// // +//////////////////////////////////////////////////////////////////////////////// + +// This defines has been moved to P7_Client.h to be visible from outside the +// library +// #define USER_PACKET_CHANNEL_ID_BITS_COUNT (5) +// #define USER_PACKET_SIZE_BITS_COUNT (32-USER_PACKET_CHANNEL_ID_BITS_COUNT) +// #define USER_PACKET_MAX_SIZE (1 << USER_PACKET_SIZE_BITS_COUNT) +// #define USER_PACKET_CHANNEL_ID_MAX_SIZE (1 << USER_PACKET_CHANNEL_ID_BITS_COUNT) + +#define INIT_USER_HEADER(iSize, iChannel_Id) (iSize | (iChannel_Id << USER_PACKET_SIZE_BITS_COUNT)) +#define GET_USER_HEADER_SIZE(iBits) (iBits & ((1 << USER_PACKET_SIZE_BITS_COUNT) - 1)) +#define GET_USER_HEADER_CHANNEL_ID(iBits) ((iBits >> USER_PACKET_SIZE_BITS_COUNT) & ((1 << USER_PACKET_CHANNEL_ID_BITS_COUNT) - 1)) + +#define CHANNEL_PACKETS_UNION_MAX_SIZE (128 * 1024) + +struct sH_User_Raw //user data header +{ + tUINT32 dwBits; +} ATTR_PACK(2); + +struct sH_User_Data //user data header, map for sH_User_Raw +{ + tUINT32 dwSize :USER_PACKET_SIZE_BITS_COUNT; //<< 28 bits for Size + tUINT32 dwChannel_ID :USER_PACKET_CHANNEL_ID_BITS_COUNT; //<< 5 bits for ChannelId +} ATTR_PACK(2); + +GASSERT(sizeof(sH_User_Data) == sizeof(sH_User_Raw)); + +PRAGMA_PACK_EXIT() + + + + +//////////////////////////////////////////////////////////////////////////////// +// CTPacket for providing basic functionality over tH_Common packet's header +class CTPacket +{ +protected: + tUINT8 *m_pBuffer; + tUINT32 m_dwBuffer_Size; + tBOOL m_bInitialized; + tUINT32 m_dwPool_ID; + tBOOL m_bShell; + sH_Common *m_pHeader; //point to m_pBuffer +public: + //////////////////////////////////////////////////////////////////////////// + //CTPacket::CTPacket + CTPacket() + : m_pBuffer(NULL) + , m_dwBuffer_Size(0) + , m_bInitialized(TRUE) + , m_dwPool_ID(0) + , m_bShell(TRUE) + , m_pHeader(NULL) + { + }//CTPacket::CTPacket + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::CTPacket + CTPacket(tUINT8 *i_pBuffer, + tUINT32 i_dwBuffer_Size, + tUINT32 i_dwPool_ID + ) + : m_pBuffer(i_pBuffer) + , m_dwBuffer_Size(i_dwBuffer_Size) + , m_bInitialized(TRUE) + , m_dwPool_ID(i_dwPool_ID) + , m_bShell(TRUE) + , m_pHeader(NULL) + { + if (m_pBuffer) + { + m_bInitialized = TRUE; + memset(m_pBuffer, 0, m_dwBuffer_Size); + m_pHeader = (sH_Common*)m_pBuffer; + } + else + { + m_bInitialized = FALSE; + } + }//CTPacket::CTPacket + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::CTPacket + CTPacket(tUINT32 i_dwBuffer_Size, tUINT32 i_dwPool_ID) + : m_pBuffer(NULL) + , m_dwBuffer_Size(0) + , m_bInitialized(FALSE) + , m_dwPool_ID(i_dwPool_ID) + , m_bShell(FALSE) + , m_pHeader(NULL) + { + m_pBuffer = new tUINT8[i_dwBuffer_Size]; + + if (m_pBuffer) + { + m_dwBuffer_Size = i_dwBuffer_Size; + m_bInitialized = TRUE; + memset(m_pBuffer, 0, m_dwBuffer_Size); + m_pHeader = (sH_Common*)m_pBuffer; + } + }//CTPacket::CTPacket + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::~CTPacket + virtual ~CTPacket() + { + if ( (FALSE == m_bShell) + && (NULL != m_pBuffer) + ) + { + delete [] m_pBuffer; + m_pBuffer = NULL; + } + + m_dwBuffer_Size = 0; + m_bInitialized = FALSE; + m_dwPool_ID = 0; + m_pHeader = NULL; + } //CTPacket::~CTPacket + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Chage_Endianness + virtual void Chage_Endianness() + { + m_pHeader->dwCRC32 = ntohl(m_pHeader->dwCRC32); + m_pHeader->dwID = ntohl(m_pHeader->dwID); + m_pHeader->wBits = ntohs(m_pHeader->wBits); + m_pHeader->wClient_ID = ntohs(m_pHeader->wClient_ID); + m_pHeader->wSize = ntohs(m_pHeader->wSize); + } + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Initialized + inline tBOOL Get_Initialized() + { + return m_bInitialized; + } //CTPacket::Get_Initialized + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Finalize + virtual void Finalize(tUINT32 i_dwPacket_ID, tUINT16 i_wClient_ID) + { + m_pHeader->dwID = i_dwPacket_ID; + m_pHeader->wClient_ID = i_wClient_ID; + m_pHeader->dwCRC32 = Calculate_CRC(m_pHeader->wSize); + }//CTPacket::Finalize + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Size + inline tUINT16 Get_Size() + { + return m_pHeader->wSize; + }//CTPacket::Get_Size + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Client_ID + inline tUINT16 Get_Client_ID() + { + return m_pHeader->wClient_ID; + }//CTPacket::Get_Client_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Type + inline eTPacket_Type Get_Type() + { + return (eTPacket_Type)(m_pHeader->wBits & TPACKET_TYPE_MASK); + }//CTPacket::Get_Type + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Set_Type + inline void Set_Type(eTPacket_Type i_eType) + { + m_pHeader->wBits &= ~TPACKET_TYPE_MASK; //clear type + m_pHeader->wBits |= (i_eType & TPACKET_TYPE_MASK); //set new one + }//CTPacket::Get_Flags + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_ID + inline tUINT32 Get_ID() + { + return m_pHeader->dwID; + }//CTPacket::Get_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Is_Damaged + inline tBOOL Is_Damaged() + { + return (Calculate_CRC(m_pHeader->wSize) != m_pHeader->dwCRC32); + }//CTPacket::Is_Damaged + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Is_Damaged + inline tBOOL Is_Damaged(tBOOL i_bSwapBytes) + { + if (i_bSwapBytes) + { + return (Calculate_CRC(ntohs(m_pHeader->wSize)) != ntohl(m_pHeader->dwCRC32)); + } + else + { + return (Calculate_CRC(m_pHeader->wSize) != m_pHeader->dwCRC32); + } + }//CTPacket::Is_Damaged + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Flags + inline tUINT16 Get_Flags() + { + return (m_pHeader->wBits & TPACKET_FLAGS_MASK) >> TPACKET_FLAGS_OFFSET; + }//CTPacket::Get_Flags + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Set_Flag + inline void Set_Flag(tUINT16 i_wFlag) + { + m_pHeader->wBits |= (i_wFlag << TPACKET_FLAGS_OFFSET) & TPACKET_FLAGS_MASK; + }//CTPacket::Get_Flags + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Clr_Flag + inline void Clr_Flag(tUINT16 i_wFlag) + { + m_pHeader->wBits &= ~((i_wFlag << TPACKET_FLAGS_OFFSET) & TPACKET_FLAGS_MASK); + }//CTPacket::Get_Flags + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Buffer + inline tUINT8 *Get_Buffer() + { + return m_pBuffer; + }//CTPacket::Get_Buffer + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Buffer + inline tUINT32 Get_Crc() + { + return m_pHeader->dwCRC32; + }//CTPacket::Get_Buffer + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Buffer_Size + inline tUINT32 Get_Buffer_Size() + { + return m_dwBuffer_Size; + }//CTPacket::Get_Buffer_Size + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Get_Pool_ID + inline tUINT32 Get_Pool_ID() + { + return m_dwPool_ID; + }//CTPacket::Get_Pool_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Attach + virtual tBOOL Attach(CTPacket *i_pPacket) + { + if ( (NULL == i_pPacket) + || (FALSE == m_bShell) + ) + { + return FALSE; + } + + m_pBuffer = i_pPacket->m_pBuffer; + m_dwBuffer_Size = i_pPacket->m_dwBuffer_Size; + m_pHeader = (sH_Common*)m_pBuffer; + m_dwPool_ID = i_pPacket->m_dwPool_ID; + + return (NULL != m_pBuffer); + }//CTPacket::Attach + + + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Detach + inline tBOOL Detach() + { + if (FALSE == m_bShell) + { + return FALSE; + } + + m_pBuffer = NULL; + m_dwBuffer_Size = 0; + m_pHeader = NULL; + m_dwPool_ID = 0; + + return TRUE; + }//CTPacket::Detach + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Add_Extra + inline tBOOL Add_Extra(const tUINT8 *i_pData, tUINT16 i_dwSize, tUINT16 i_wFlag) + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + || (NULL == i_pData) + || (0 >= i_dwSize) + || ((m_dwBuffer_Size - m_pHeader->wSize ) < i_dwSize) + ) + { + return FALSE; + } + + memcpy(m_pBuffer + m_pHeader->wSize, i_pData, i_dwSize); + m_pHeader->wSize = (tUINT16)(m_pHeader->wSize + i_dwSize); + CTPacket::Set_Flag(i_wFlag); + return TRUE; + }//CTPClient_Data_Report::Add_Extra + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Clr_Extra + inline void Clr_Extra() + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + ) + { + return; + } + + CTPacket::Clr_Flag(TPACKET_FLAG_EXTRA_DATA); + CTPacket::Clr_Flag(TPACKET_FLAG_EXTENSION); + }//CTPClient_Data_Report::Clr_Extra + + +protected: + //////////////////////////////////////////////////////////////////////////// + //CTPacket::Calculate_CRC + inline tUINT32 Calculate_CRC(size_t i_szLength) + { + size_t l_szOffset = offsetof(sH_Common, dwCRC32) + sizeof(m_pHeader->dwCRC32); + + //this is absolute minimum size of the packet + if (sizeof(sH_Common) > i_szLength) + { + i_szLength = sizeof(sH_Common); + } + + return Get_CRC32(m_pBuffer + l_szOffset, i_szLength - l_szOffset); + }//CTPacket::Calculate_CRC +};//CTPacket + + + + + +////////////////////////////////////////////////////////////////////////////*** +// Class for providing basic functionality over tH_Client_Initial packet's +// header +#define CLIENT_INITIAL_SIZE (sizeof(sH_Client_Hello) + sizeof(sH_Common)) + +class CTPClient_Hello: public CTPacket +{ + sH_Client_Hello *m_pInitial; +public: + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::CTPClient_Hello + //stationary packet, it belong to stream + CTPClient_Hello(): + CTPacket(CLIENT_INITIAL_SIZE, 0) + ,m_pInitial(NULL) + { + if (m_pHeader) + { + m_pHeader->wSize = CLIENT_INITIAL_SIZE; + CTPacket::Set_Type(ETPT_CLIENT_HELLO); + + m_pInitial = (sH_Client_Hello*)(m_pBuffer + sizeof(sH_Common)); + } + }//CTPClient_Hello::CTPClient_Hello + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::CTPClient_Hello + //dynamic packet, it belong to Pool + CTPClient_Hello(CTPacket *i_pPacket): + CTPacket() + ,m_pInitial(NULL) + { + m_bInitialized = Attach(i_pPacket); + if (m_bInitialized) + { + m_pInitial = (sH_Client_Hello*)(m_pBuffer + sizeof(sH_Common)); + } + }//CTPClient_Hello::CTPClient_Hello + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Chage_Endianness + virtual void Chage_Endianness() + { + m_pInitial->wProtocol_Version = ntohs(m_pInitial->wProtocol_Version); + m_pInitial->wData_Max_Size = ntohs(m_pInitial->wData_Max_Size); + m_pInitial->dwProcess_ID = ntohl(m_pInitial->dwProcess_ID); + m_pInitial->dwProcess_Start_Time_Hi = ntohl(m_pInitial->dwProcess_Start_Time_Hi); + m_pInitial->dwProcess_Start_Time_Lo = ntohl(m_pInitial->dwProcess_Start_Time_Lo); + + tWCHAR *l_pBegin = m_pInitial->pProcess_Name; + tWCHAR *l_pEnd = m_pInitial->pProcess_Name + TPACKET_PROCESS_NAME_MAX_LEN; + + while ( (*l_pBegin) + && (l_pBegin < l_pEnd) + ) + { + *l_pBegin = ntohs(*l_pBegin); + + l_pBegin ++; + } + } + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Fill + inline tBOOL Fill(tUINT16 i_wProtocol_Version, + tUINT16 i_wData_Max_Size, + tUINT32 i_dwProcess_ID, + tUINT32 i_dwProcess_Start_Time_Hi, + tUINT32 i_dwProcess_Start_Time_Lo, + tWCHAR *i_pProcess_Name //[TPACKET_PROCESS_NAME_MAX_LEN] + ) + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + || (NULL == i_pProcess_Name) + ) + { + return FALSE; + } + + m_pInitial->wProtocol_Version = i_wProtocol_Version; + m_pInitial->wData_Max_Size = i_wData_Max_Size; + m_pInitial->dwProcess_ID = i_dwProcess_ID; + m_pInitial->dwProcess_Start_Time_Hi = i_dwProcess_Start_Time_Hi; + m_pInitial->dwProcess_Start_Time_Lo = i_dwProcess_Start_Time_Lo; + + tWCHAR *l_pSrc = i_pProcess_Name; + tWCHAR *l_pDst = m_pInitial->pProcess_Name; + tUINT16 l_wRst = TPACKET_PROCESS_NAME_MAX_LEN - 1; + + //wcsncpy_s(m_pInitial->pProcess_Name, + // TPACKET_PROCESS_NAME_MAX_LEN, + // i_pProcess_Name, + // TPACKET_PROCESS_NAME_MAX_LEN - 1 + // ); + while ( (l_wRst) + && (*l_pSrc) + ) + { + *l_pDst = *l_pSrc; + l_pDst ++; + l_pSrc ++; + l_wRst --; + } + + *l_pDst = 0; + + return TRUE; + } //CTPClient_Hello::Fill + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Fill + inline tUINT16 Get_Protocol_Version() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pInitial->wProtocol_Version; + }//CTPClient_Hello::Fill + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Get_Data_Max_Size + inline tUINT16 Get_Data_Max_Size() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pInitial->wData_Max_Size; + }//CTPClient_Hello::Get_Data_Max_Size + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Get_Process_ID + inline tUINT32 Get_Process_ID() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pInitial->dwProcess_ID; + }//CTPClient_Hello::Get_Process_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Get_Process_Time_Hi + inline tUINT32 Get_Process_Time_Hi() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pInitial->dwProcess_Start_Time_Hi; + }//CTPClient_Hello::Get_Process_Times + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Get_Process_Time_Low + inline tUINT32 Get_Process_Time_Low() + { + if (FALSE == m_bInitialized) + + { + return 0; + } + + return m_pInitial->dwProcess_Start_Time_Lo; + }//CTPClient_Hello::Get_Process_Times + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Hello::Get_Process_Name + inline tWCHAR *Get_Process_Name() + { + if (FALSE == m_bInitialized) + { + return NULL; + } + + return m_pInitial->pProcess_Name; + }//CTPClient_Hello::Get_Process_Name +}; //CTPClient_Hello + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over client data packets +#define CLIENT_DATA_HEADER_SIZE sizeof(sH_Common) + +class CTPData: public CTPacket +{ +public: + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::CTPClient_Data + CTPData(CTPacket *i_pPacket): + CTPacket() + { + m_bInitialized = Attach(i_pPacket); + }//CTPClient_Data::CTPClient_Data + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::CTPClient_Data + CTPData(): + CTPacket() + { + }//CTPClient_Data::CTPClient_Data + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Attach + inline tBOOL Attach(CTPacket *i_pPacket) + { + m_bInitialized = CTPacket::Attach(i_pPacket); + return m_bInitialized; + }//CTPClient_Data::Attach + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Initialize + inline void Initialize() + { + if (m_pHeader) + { + m_pHeader->wSize = sizeof(sH_Common); + CTPacket::Set_Type(ETPT_CLIENT_DATA); + } + }//CTPClient_Data::Initialize + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Get_Data + inline tUINT8 *Get_Data() + { + if ( (NULL == m_pBuffer) + || (m_dwBuffer_Size <= sizeof(sH_Common)) + ) + { + return NULL; + } + + return m_pBuffer + sizeof(sH_Common); + }//CTPClient_Data::Get_Data + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Get_Data_Size + inline tUINT16 Get_Data_Size() + { + if (NULL == m_pHeader) + { + return 0; + } + + return m_pHeader->wSize - sizeof(sH_Common); + }//CTPClient_Data::Get_Data_Size + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Get_Tail + inline tUINT8 *Get_Tail() + { + if ( (NULL == m_pBuffer) + || (m_pHeader->wSize >= m_dwBuffer_Size) + ) + { + return NULL; + } + + return m_pBuffer + m_pHeader->wSize; + }//CTPClient_Data::Get_Tail + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Get_Tail_Size + inline tUINT16 Get_Tail_Size() + { + if (NULL == m_pHeader) + { + return 0; + } + + return (tUINT16)(m_dwBuffer_Size - m_pHeader->wSize); + }//CTPClient_Data::Get_Tail_Size + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Append_Size + inline tBOOL Append_Size(tUINT16 i_wSize) + { + if ( (NULL == m_pHeader) + || ( i_wSize > Get_Tail_Size() ) + ) + { + return FALSE; + } + + m_pHeader->wSize += i_wSize; + return TRUE; + }//CTPClient_Data::Append_Size + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data::Finalize + inline void Finalize(tUINT32 i_dwPacket_ID, tUINT16 i_wClient_ID) + { + if (m_pHeader) + { + CTPacket::Set_Type(ETPT_CLIENT_DATA); + CTPacket::Finalize(i_dwPacket_ID, i_wClient_ID); + } + }//CTPClient_Data::Finalize +};//CTPClient_Data + + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over client data report packet +#define CLIENT_DATA_REPORT_SIZE (sizeof(sH_Data_Window) + sizeof(sH_Common)) +class CTPData_Window: public CTPacket +{ + sH_Data_Window *m_pReport; +public: + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data_Report::CTPClient_Data_Report + //stationary packet, it belong to stream + CTPData_Window(): + CTPacket(CLIENT_DATA_REPORT_SIZE, 0) + ,m_pReport(NULL) + { + if (m_bInitialized) + { + m_pHeader->wSize = CLIENT_DATA_REPORT_SIZE; + CTPacket::Set_Type(ETPT_CLIENT_DATA_REPORT); + + m_pReport = (sH_Data_Window*)(m_pBuffer + sizeof(sH_Common)); + } + }//CTPClient_Data_Report::CTPClient_Data_Report + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data_Report::CTPClient_Data_Report + //dynamic packet, it belong to Pool + CTPData_Window(CTPacket *i_pPacket): + CTPacket() + ,m_pReport(NULL) + { + m_bInitialized = Attach(i_pPacket); + if (m_bInitialized) + { + m_pReport = (sH_Data_Window*)(m_pBuffer + sizeof(sH_Common)); + } + }//CTPClient_Data_Report::CTPClient_Data_Report + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data_Report::Fill + inline tBOOL Fill(tUINT32 i_dwData_First_ID, tUINT32 i_dwData_Last_ID) + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + ) + { + return FALSE; + } + + m_pReport->dwFirst_ID = i_dwData_First_ID; + m_pReport->dwLast_ID = i_dwData_Last_ID; + + return TRUE; + } + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data_Report::Chage_Endianness + virtual void Chage_Endianness() + { + m_pReport->dwFirst_ID = ntohl(m_pReport->dwFirst_ID); + m_pReport->dwLast_ID = ntohl(m_pReport->dwLast_ID); + }//CTPClient_Data_Report::Chage_Endianness + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data_Report::Get_First_ID + inline tUINT32 Get_First_ID() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pReport->dwFirst_ID; + }//CTPClient_Data_Report::Get_First_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Data_Report::Get_Last_ID + inline tUINT32 Get_Last_ID() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pReport->dwLast_ID; + }//CTPClient_Data_Report::Get_Last_ID +};//CTPClient_Data_Report + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over client alive packet +#define CLIENT_ALIVE_SIZE (sizeof(sH_Common)) +class CTPClient_Ping: public CTPacket +{ +public: + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Ping::CTPClient_Ping + //stationary packet, it belong to stream + CTPClient_Ping(): + CTPacket(CLIENT_ALIVE_SIZE, 0) + { + if (m_bInitialized) + { + m_pHeader->wSize = CLIENT_ALIVE_SIZE; + CTPacket::Set_Type(ETPT_CLIENT_PING); + } + }//CTPClient_Ping::CTPClient_Ping +}; + + + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over client bye packet +#define CLIENT_BYE_SIZE (sizeof(sH_Common)) +class CTPClient_Bye: public CTPacket +{ +public: + //////////////////////////////////////////////////////////////////////////// + //CTPClient_Ping::CTPClient_Ping + //stationary packet, it belong to stream + CTPClient_Bye(): + CTPacket(CLIENT_BYE_SIZE, 0) + { + if (m_bInitialized) + { + m_pHeader->wSize = CLIENT_BYE_SIZE; + CTPacket::Set_Type(ETPT_CLIENT_BYE); + } + }//CTPClient_Ping::CTPClient_Ping +};//CTPClient_Ping + + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over server response packet +#define ACKNOWLEDGMENT_SIZE (sizeof(sH_Packet_Ack) + sizeof(sH_Common)) +class CTPAcknowledgment: + public CTPacket +{ + sH_Packet_Ack *m_pResponse; +public: + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::CTPServer_Response + //stationary packet, it belong to stream + CTPAcknowledgment(tUINT32 i_uBufferSize = TPACKET_MIN_SIZE, tUINT32 i_uPoolId = 0) + : CTPacket(i_uBufferSize, i_uPoolId) + , m_pResponse(NULL) + { + if (m_bInitialized) + { + Reset(); + m_pResponse = (sH_Packet_Ack*)(m_pBuffer + sizeof(sH_Common)); + } + }//CTPServer_Response::CTPServer_Response + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::CTPServer_Response + //dynamic packet, it belong to Pool + CTPAcknowledgment(CTPacket *i_pPacket): + CTPacket() + ,m_pResponse(NULL) + { + m_bInitialized = Attach(i_pPacket); + if (m_bInitialized) + { + m_pResponse = (sH_Packet_Ack*)(m_pBuffer + sizeof(sH_Common)); + } + }//CTPServer_Response::CTPServer_Response + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Reset + inline void Reset() + { + m_pHeader->dwCRC32 = 0u; + m_pHeader->dwID = 0u; + m_pHeader->wBits = 0; + m_pHeader->wClient_ID = 0; + m_pHeader->wSize = ACKNOWLEDGMENT_SIZE; + CTPacket::Set_Type(ETPT_ACKNOWLEDGMENT); + } + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Fill + inline tBOOL Fill(tUINT32 i_dwSource_ID, tUINT16 i_wResult) + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + ) + { + return FALSE; + } + + m_pResponse->dwSource_ID = i_dwSource_ID; + m_pResponse->wResult = i_wResult; + + return TRUE; + } + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Chage_Endianness + virtual void Chage_Endianness() + { + m_pResponse->dwSource_ID = ntohl(m_pResponse->dwSource_ID); + m_pResponse->wResult = ntohs(m_pResponse->wResult); + }//CTPServer_Response::Chage_Endianness + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Get_Source_ID + inline tUINT32 Get_Source_ID() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pResponse->dwSource_ID; + }//CTPClient_Data_Report::Get_Source_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Get_Result + inline tUINT16 Get_Result() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pResponse->wResult; + }//CTPClient_Data_Report::Get_Result + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Response::Finalize + virtual void Finalize(tUINT32 i_dwPacket_ID, + tUINT16 i_wClient_ID, + tBOOL i_bSwapBytes) + { + m_pHeader->dwID = i_dwPacket_ID; + m_pHeader->wClient_ID = i_wClient_ID; + + if (!i_bSwapBytes) + { + m_pHeader->dwCRC32 = Calculate_CRC(m_pHeader->wSize); + } + else + { + CTPacket::Chage_Endianness(); + Chage_Endianness(); + m_pHeader->dwCRC32 = ntohl(Calculate_CRC(ntohs(m_pHeader->wSize))); + } + }//CTPServer_Response::Finalize +};//CTPServer_Response + + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over server report packet +#define SERVER_REPORT_SIZE (TPACKET_MIN_SIZE) +#define SERVER_REPORT_HEADER_SIZE (sizeof(sH_Common) +\ + offsetof(sH_Data_Window_Report, pID)) + +class CTPData_Window_Report: + public CTPacket +{ + sH_Data_Window_Report *m_pReport; + tUINT32 m_dwCount; +public: + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::CTPServer_Report + //stationary packet, it belong to stream + CTPData_Window_Report() + : CTPacket(SERVER_REPORT_SIZE, 0) + , m_pReport(NULL) + , m_dwCount(0) + { + if (m_bInitialized) + { + Reset(); + + m_pReport = (sH_Data_Window_Report*)(m_pBuffer + sizeof(sH_Common)); + m_dwCount = m_pHeader->wSize - SERVER_REPORT_HEADER_SIZE; + } + }//CTPServer_Report::CTPServer_Report + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::CTPServer_Report + //dynamic packet, it belong to Pool + CTPData_Window_Report(CTPacket *i_pPacket): + CTPacket() + ,m_pReport(NULL) + ,m_dwCount(0) + { + m_bInitialized = Attach(i_pPacket); + if (m_bInitialized) + { + m_pReport = (sH_Data_Window_Report*)(m_pBuffer + sizeof(sH_Common)); + m_dwCount = m_pHeader->wSize - SERVER_REPORT_HEADER_SIZE; + } + }//CTPServer_Report::CTPServer_Report + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Reset + inline void Reset() + { + m_pHeader->dwCRC32 = 0u; + m_pHeader->dwID = 0u; + m_pHeader->wBits = 0; + m_pHeader->wClient_ID = 0; + m_pHeader->wSize = SERVER_REPORT_SIZE; + + CTPacket::Set_Type(ETPT_SERVER_DATA_REPORT); + }//CTPServer_Report::Reset + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Is_ID + inline tBOOL Is_ID(tUINT32 i_dwFirst_ID, tUINT32 i_dwCurrent_ID) + { + tUINT32 l_dwOffset = ID_Difference(i_dwFirst_ID, i_dwCurrent_ID); + + if ( (NULL == m_pReport) + || (l_dwOffset >= (m_dwCount << 3)) + ) + { + return FALSE; + } + + return ( 0 != (m_pReport->pID[l_dwOffset >> 3] & (1 << (l_dwOffset % 8))) ); + }//CTPServer_Report::Is_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Clr_IDs + inline tBOOL Clr_IDs() + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + ) + { + return FALSE; + } + + memset(m_pReport->pID, 0, m_dwCount); + + return TRUE; + } //Clr_IDs + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Set_ID + inline tBOOL Set_ID(tUINT32 i_dwFirst_ID, tUINT32 i_dwCurrent_ID) + { + tUINT32 l_dwOffset = ID_Difference(i_dwFirst_ID, i_dwCurrent_ID); + + if ( (NULL == m_pReport) + || (l_dwOffset >= (m_dwCount << 3)) + ) + { + return FALSE; + } + + m_pReport->pID[l_dwOffset >> 3] |= (1 << (l_dwOffset % 8)); + return TRUE; + }//CTPServer_Report::Set_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Get_Source_ID + inline tUINT32 Get_Source_ID() + { + if (FALSE == m_bInitialized) + { + return 0; + } + + return m_pReport->dwSource_ID; + }//CTPServer_Report::Get_Source_ID + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Fill + inline tBOOL Fill(tUINT32 i_dw_Source_ID) + { + if ( (FALSE == m_bInitialized) + || (TRUE == m_bShell) + ) + { + return FALSE; + } + + m_pReport->dwSource_ID = i_dw_Source_ID; + return TRUE; + }//CTPServer_Report::Fill + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Finalize + virtual void Finalize(tUINT32 i_dwPacket_ID, + tUINT16 i_wClient_ID, + tBOOL i_bSwapBytes) + { + m_pHeader->dwID = i_dwPacket_ID; + m_pHeader->wClient_ID = i_wClient_ID; + + if (!i_bSwapBytes) + { + m_pHeader->dwCRC32 = Calculate_CRC(m_pHeader->wSize); + } + else + { + CTPacket::Chage_Endianness(); + Chage_Endianness(); + m_pHeader->dwCRC32 = ntohl(Calculate_CRC(ntohs(m_pHeader->wSize))); + } + }//CTPServer_Report::Finalize + + + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::Chage_Endianness + virtual void Chage_Endianness() + { + m_pReport->dwSource_ID = ntohl(m_pReport->dwSource_ID); + }//CTPServer_Report::Chage_Endianness + + +private: + //////////////////////////////////////////////////////////////////////////// + //CTPServer_Report::ID_Difference + inline tUINT32 ID_Difference(tUINT32 i_dwFirst_ID, tUINT32 i_dwCurrent_ID) + { + if (i_dwCurrent_ID < i_dwFirst_ID) + { + return ((TPACKET_MAX_ID - i_dwFirst_ID) + i_dwCurrent_ID); + } + + return (i_dwCurrent_ID - i_dwFirst_ID); + }//CTPServer_Report::ID_Difference + +};//CTPServer_Report + + + +//////////////////////////////////////////////////////////////////////////////// +// Class for providing basic functionality over server info ext packet +#define EXT_SRV_INFO_SIZE (sizeof(sH_Ext) + sizeof(sH_Ext_Srv_Info)) +class CTPESrv_Info +{ + size_t m_szMax; + tUINT8 m_pBuffer[sizeof(sH_Ext) + sizeof(sH_Ext_Srv_Info)]; + sH_Ext *m_pExt; + sH_Ext_Srv_Info *m_pInfo; +public: + //////////////////////////////////////////////////////////////////////////// + //CTPESrv_Info::CTPESrv_Info + //stationary packet, it belong to stream + CTPESrv_Info() + : m_szMax(sizeof(sH_Ext) + sizeof(sH_Ext_Srv_Info)) + , m_pExt(NULL) + , m_pInfo(NULL) + { + memset(m_pBuffer, 0, m_szMax); + m_pExt = (sH_Ext*)m_pBuffer; + m_pInfo = (sH_Ext_Srv_Info*)(m_pBuffer + sizeof(sH_Ext)); + m_pExt->wSize = (tUINT16)m_szMax; + m_pExt->wType = ETPE_SERVER_NETWORK_INFO; + }//CTPESrv_Info::CTPESrv_Info + + //////////////////////////////////////////////////////////////////////////// + //CTPESrv_Info::Fill + inline void Fill(tUINT32 i_dwServerV, tUINT16 i_wProtocolV, tUINT16 i_wMTU, tUINT32 i_dwSocketBuffer) + { + m_pInfo->dwServerVersion = i_dwServerV; + m_pInfo->dwSocket_Buffer = i_dwSocketBuffer; + m_pInfo->wMTU = i_wMTU; + m_pInfo->wProtocolVersion = i_wProtocolV; + } + + //////////////////////////////////////////////////////////////////////////// + //CTPESrv_Info::Chage_Endianness + virtual void Chage_Endianness() + { + m_pExt->wSize = ntohs(m_pExt->wSize); + m_pExt->wType = ntohs(m_pExt->wType); + m_pInfo->dwServerVersion = ntohl(m_pInfo->dwServerVersion); + m_pInfo->dwSocket_Buffer = ntohl(m_pInfo->dwSocket_Buffer); + m_pInfo->wMTU = ntohs(m_pInfo->wMTU); + m_pInfo->wProtocolVersion = ntohs(m_pInfo->wProtocolVersion); + }//CTPESrv_Info::Chage_Endianness + + //////////////////////////////////////////////////////////////////////////// + //CTPESrv_Info::GetBuffer + inline const tUINT8 *GetBuffer() + { + return m_pBuffer; + } + + //////////////////////////////////////////////////////////////////////////// + //CTPESrv_Info::GetBufferSize + inline size_t GetBufferSize() + { + return m_szMax; + } +};//CTPESrv_Info + + + +#if defined(_DEBUG) || defined(DEBUG) + #define PACKET_PRINT(i_Log, i_Prefix, i_Packet) Packet_Print(i_Log,i_Prefix, i_Packet); +#else + #define PACKET_PRINT(i_Log, i_Prefix, i_Packet) +#endif + +inline void Packet_Print(IJournal *i_pLog, + const tXCHAR *l_pPrefix, + CTPacket *i_pPacket) +{ + if ( (NULL == i_pLog) + || (IJournal::eLEVEL_TRACE < i_pLog->Get_Verbosity()) + || (NULL == i_pPacket) + ) + { + return; + } + + eTPacket_Type l_eType = i_pPacket->Get_Type(); + + switch (l_eType) + { + case ETPT_CLIENT_HELLO: + { + CTPClient_Hello l_cHello(i_pPacket); + + JOURNAL_DEBUG(i_pLog, + TM("%s [Initial] ID=%d, Size=%d, Protocol=%d, MaxSize=%d Process[%d/%s]"), + l_pPrefix, + (tUINT32)l_cHello.Get_ID(), + (tUINT32)l_cHello.Get_Size(), + (tUINT32)l_cHello.Get_Protocol_Version(), + (tUINT32)l_cHello.Get_Data_Max_Size(), + (tUINT32)l_cHello.Get_Process_ID(), + l_cHello.Get_Process_Name() + ); + break; + } + case ETPT_CLIENT_PING: + { + JOURNAL_DEBUG(i_pLog, + TM("%s [Alive] ID=%d, Size=%d"), + l_pPrefix, + (tUINT32)i_pPacket->Get_ID(), + (tUINT32)i_pPacket->Get_Size() + ); + break; + } + case ETPT_CLIENT_DATA: + { + break; + } + case ETPT_CLIENT_DATA_REPORT: + { + CTPData_Window l_cReport(i_pPacket); + JOURNAL_DEBUG(i_pLog, + TM("%s [Data report] ID=%d, Size=%d, window ID [%d .. %d]"), + l_pPrefix, + (tUINT32)l_cReport.Get_ID(), + (tUINT32)l_cReport.Get_Size(), + (tUINT32)l_cReport.Get_First_ID(), + (tUINT32)l_cReport.Get_Last_ID() + ); + break; + } + case ETPT_CLIENT_BYE: + { + JOURNAL_DEBUG(i_pLog, + TM("%s [Bye] ID=%d, Size=%d"), + l_pPrefix, + (tUINT32)i_pPacket->Get_ID(), + (tUINT32)i_pPacket->Get_Size() + ); + break; + } + case ETPT_ACKNOWLEDGMENT: + { + CTPAcknowledgment l_cResponse(i_pPacket); + JOURNAL_DEBUG(i_pLog, + TM("%s [Response] ID=%d, Size=%d, Source ID=%d Result=%d"), + l_pPrefix, + (tUINT32)l_cResponse.Get_ID(), + (tUINT32)l_cResponse.Get_Size(), + (tUINT32)l_cResponse.Get_Source_ID(), + (tUINT32)l_cResponse.Get_Result() + ); + break; + } + case ETPT_SERVER_DATA_REPORT: + { + CTPData_Window_Report l_cReport(i_pPacket); + JOURNAL_DEBUG(i_pLog, + TM("%s [Data report] ID=%d, Size=%d, Source ID=%d"), + l_pPrefix, + (tUINT32)l_cReport.Get_ID(), + (tUINT32)l_cReport.Get_Size(), + (tUINT32)l_cReport.Get_Source_ID() + ); + break; + } + case ETPT_SERVER_CHAINED: + { + break; + } + default: + { + JOURNAL_DEBUG(i_pLog, + TM("%s [Unknown] ID=%d, Size=%d"), + l_pPrefix, + (tUINT32)i_pPacket->Get_ID(), + (tUINT32)i_pPacket->Get_Size() + ); + break; + } + } +} + +#endif //TPACKETS_H diff --git a/p7lib/Sources/Telemetry.cpp b/p7lib/Sources/Telemetry.cpp new file mode 100644 index 0000000..e1bde55 --- /dev/null +++ b/p7lib/Sources/Telemetry.cpp @@ -0,0 +1,1181 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This file provide telemetry functionality / +//////////////////////////////////////////////////////////////////////////////// +#include "CommonClient.h" +#include "Telemetry.h" + + +#define RESET_UNDEFINED (0xFFFFFFFFUL) +#define RESET_FLAG_HEADER (0x1) +#define RESET_FLAG_COUNTER (0x2) +#define TELEMETRY_SHARED_PREFIX TM("Tel_") +#define TELEMETRY_ON_CONNECT_EXIT_SIGNAL (MEVENT_SIGNAL_0) + +extern "C" +{ + +//////////////////////////////////////////////////////////////////////////////// +//P7_Create_Telemetry +P7_EXPORT IP7_Telemetry * __cdecl P7_Create_Telemetry(IP7_Client *i_pClient, + const tXCHAR *i_pName, + const stTelemetry_Conf *i_pConf + ) +{ + //telemetry isn't supported by next sinks + if ( (!i_pClient) + || (IP7_Client::eText <= i_pClient->Get_Type()) + ) + { + return NULL; + } + + //Check parameters + if (i_pConf) + { + if ( ( (!i_pConf->qwTimestamp_Frequency) + && (i_pConf->pTimestamp_Callback) + ) + || ( (i_pConf->qwTimestamp_Frequency) + && (!i_pConf->pTimestamp_Callback) + ) + ) + { + return NULL; + } + } + + CP7Telemetry *l_pReturn = new CP7Telemetry(i_pClient, i_pName, i_pConf); + + //if not initialized - remove + if ( (l_pReturn) + && (TRUE != l_pReturn->Is_Initialized()) + ) + { + l_pReturn->Release(); + l_pReturn = NULL; + } + + return static_cast(l_pReturn); +}//P7_Create_Telemetry + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Get_Shared_Telemetry +P7_EXPORT IP7_Telemetry * __cdecl P7_Get_Shared_Telemetry(const tXCHAR *i_pName) +{ + IP7_Telemetry *l_pReturn = NULL; + tUINT32 l_dwLen1 = PStrLen(TELEMETRY_SHARED_PREFIX); + tUINT32 l_dwLen2 = PStrLen(i_pName); + tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + sObjShared l_stShared = {}; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + + if (l_pName) + { + PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, TELEMETRY_SHARED_PREFIX); + PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); + if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) + { + if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) + { + if ( (l_stShared.uProcTimeHi == l_uTimeHi) + && (l_stShared.uProcTimeLo == l_uTimeLo) + ) + { + l_pReturn = static_cast(l_stShared.pPointer); + if (l_pReturn) + { + l_pReturn->Add_Ref(); + } + } + else + { + CShared::UnLink(l_pName); + } + } + + CShared::UnLock(l_hSem); + } + + free(l_pName); + l_pName = NULL; + } + + return l_pReturn; +}//P7_Get_Shared_Telemetry + +} //extern "C" + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +// CP7Tel_Counter +CP7Tel_Counter::CP7Tel_Counter(tUINT16 i_wID, + tUINT8 i_bOn, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + const tXCHAR *i_pName, + tUINT32 i_uHash + ) + : m_bInitialized(TRUE) + , m_pName(PStrDub(i_pName)) + , m_bDelivered(FALSE) + , m_pHeader(NULL) + , m_wSeqN(0) + , m_uHash(i_uHash) + , pTreeNext(NULL) +{ + size_t l_szCounter = sizeof(sP7Tel_Counter_v2) - P7TELEMETRY_COUNTER_NAME_MIN_LENGTH_V2 * sizeof(tWCHAR); + size_t l_szName = PStrLen(i_pName) + 1; + l_szCounter += l_szName * sizeof(tWCHAR); + + m_pHeader = (sP7Tel_Counter_v2*)malloc(l_szCounter); + + memset(m_pHeader, 0, l_szCounter); + + INIT_EXT_HEADER(m_pHeader->sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_COUNTER, l_szCounter); + //m_sCounter.sCommon.dwSize = sizeof(sP7Tel_Counter); + //m_sCounter.sCommon.dwType = EP7USER_TYPE_TELEMETRY; + //m_sCounter.sCommon.dwSubType = EP7TEL_TYPE_COUNTER; + + m_pHeader->wID = i_wID; + m_pHeader->bOn = i_bOn; + m_pHeader->dbMin = i_dbMin; + m_pHeader->dbAlarmMin = i_dbAlarmMin; + m_pHeader->dbMax = i_dbMax; + m_pHeader->dbAlarmMax = i_dbAlarmMax; + + PUStrCpy(m_pHeader->pName, (tUINT32)l_szName, i_pName); +} // CP7Tel_Counter + + +//////////////////////////////////////////////////////////////////////////////// +// ~CP7Tel_Counter +CP7Tel_Counter::~CP7Tel_Counter() +{ + if (m_pHeader) + { + free(m_pHeader); + m_pHeader = NULL; + } + + if (m_pName) + { + PStrFreeDub(m_pName); + m_pName = NULL; + } +}// ~CP7Trace_Item + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Hash +tUINT32 CP7Tel_Counter::Get_Hash(const tXCHAR *i_pName) +{ + //Here is RedBlackTree keys are calculated + //Hash description: http://isthe.com/chongo/tech/comp/fnv/#FNV-param + //Hash parameters investigation (collisions, randomnessification) + //http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed + //Collisions: + // - Is collisions are possible ? Yes, FNV-1a produce 4 coll. on list of + // 216,553 English words. + // - If collision happens and even calculated key is not unique - is it + // dangerous ? No, in tree we will have additional list (containing + // elementS with the same key) where exact item can be found + tUINT32 l_uReturn = 2166136261ul; + + while (*i_pName) + { + l_uReturn = (l_uReturn ^ (tUINT32)*i_pName) * 16777619ul; + i_pName++; + } + + return l_uReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Has_Name +tBOOL CP7Tel_Counter::Has_Name(const tXCHAR *i_pName) +{ + return (0 == PStrCmp(i_pName , m_pName)) ? TRUE : FALSE; +}// Has_Name + + +//////////////////////////////////////////////////////////////////////////////// +// Is_Initialized +tBOOL CP7Tel_Counter::Is_Initialized() +{ + return m_bInitialized; +}// Is_Initialized + + +//////////////////////////////////////////////////////////////////////////////// +// Enable +void CP7Tel_Counter::Enable(tUINT16 i_wOn) +{ + m_pHeader->bOn = i_wOn; +}// Enable + + + +//////////////////////////////////////////////////////////////////////////////// +// CP7Telemetry +CP7Telemetry::CP7Telemetry(IP7_Client *i_pClient, const tXCHAR *i_pName, const stTelemetry_Conf *i_pConf) + : m_lReference(1) + , m_pClient(i_pClient) + , m_dwChannel_ID(0) + , m_bInitialized(TRUE) + , m_bActive(TRUE) + , m_pCounters(256) + , m_bIsHeaderDelivered(FALSE) + , m_pChunks(NULL) + , m_dwChunks_Max_Count(64) + , m_bIs_Channel(FALSE) + , m_hShared(NULL) + , m_bOnConnect_Thread(FALSE) + , m_hOnConnect_Thread(0) //NULL +{ + if (i_pConf) + { + m_sConf = *i_pConf; + } + else + { + memset(&m_sConf, 0, sizeof(m_sConf)); + } + + memset(&m_sCS, 0, sizeof(m_sCS)); + + LOCK_CREATE(m_sCS); + + memset(&m_sHeader_Info, 0, sizeof(m_sHeader_Info)); + memset(&m_sHeader_Utc, 0, sizeof(m_sHeader_Utc)); + memset(&m_sValue, 0, sizeof(m_sValue)); + + m_pChunks = new sP7C_Data_Chunk[m_dwChunks_Max_Count]; + + m_sStatus.bConnected = TRUE; + m_sStatus.dwResets = 0; + + if (NULL == m_pClient) + { + P7_Set_Last_Error(eP7_Error_NoClient); + m_bInitialized = FALSE; + } + else + { + m_pClient->Add_Ref(); + } + + + if (m_bInitialized) + { + if (FALSE == m_cOnConnect_Event.Init(1, EMEVENT_SINGLE_MANUAL)) + { + P7_Set_Last_Error(eP7_Error_OS); + m_bInitialized = FALSE; + } + } + + if (m_bInitialized) + { + INIT_EXT_HEADER(m_sHeader_Info.sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_INFO, sizeof(sP7Tel_Info)); + //m_sHeader_Info.sCommon.dwSize = sizeof(sP7Trace_Info); + //m_sHeader_Info.sCommon.dwType = EP7USER_TYPE_TELEMETRY; + //m_sHeader_Info.sCommon.dwSubType = EP7TEL_TYPE_INFO; + + if (i_pName) + { + PUStrCpy(m_sHeader_Info.pName, P7TELEMETRY_NAME_LENGTH, i_pName); + } + else + { + PUStrCpy(m_sHeader_Info.pName, P7TELEMETRY_NAME_LENGTH, TM("Unknown")); + } + + if (m_sConf.qwTimestamp_Frequency) + { + m_sHeader_Info.qwTimer_Frequency = m_sConf.qwTimestamp_Frequency; + m_sHeader_Info.qwTimer_Value = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + else + { + m_sHeader_Info.qwTimer_Frequency = GetPerformanceFrequency(); + m_sHeader_Info.qwTimer_Value = GetPerformanceCounter(); + } + + GetEpochTime(&m_sHeader_Info.dwTime_Hi, &m_sHeader_Info.dwTime_Lo); + + m_sHeader_Info.qwFlags = P7TELEMETRY_FLAG_TIME_ZONE | P7TELEMETRY_FLAG_EXTENTION; + + INIT_EXT_HEADER(m_sHeader_Utc.sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_UTC_OFFS, sizeof(sP7Tel_Utc_Offs_V2)); + m_sHeader_Utc.iUtcOffsetSec = GetUtcOffsetSeconds(); + + INIT_EXT_HEADER(m_sValue.sCommonRaw, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_VALUE, sizeof(sP7Tel_Value_v2)); + //m_sValue.sCommon.dwSize = sizeof(sP7Tel_Value); + //m_sValue.sCommon.dwType = EP7USER_TYPE_TELEMETRY; + //m_sValue.sCommon.dwSubType = EP7TEL_TYPE_VALUE; + } + + if (m_bInitialized) + { + m_bIs_Channel = (ECLIENT_STATUS_OK == m_pClient->Register_Channel(this)); + m_bInitialized = m_bIs_Channel; + + if (!m_bInitialized) + { + P7_Set_Last_Error(eP7_Error_NoFreeChannels); + } + } + + m_bActive = m_bInitialized; +}// CP7Telemetry + + +//////////////////////////////////////////////////////////////////////////////// +// ~CP7Telemetry +CP7Telemetry::~CP7Telemetry() +{ + LOCK_ENTER(m_sCS); + LOCK_EXIT(m_sCS); + + if (m_bOnConnect_Thread) + { + m_cOnConnect_Event.Set(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); + CThShell::Close(m_hOnConnect_Thread, 1000); + m_hOnConnect_Thread = 0; + } + + if (m_hShared) + { + CShared::Close(m_hShared); + m_hShared = NULL; + } + + if (m_bIs_Channel) + { + Flush(); + + m_pClient->Unregister_Channel(m_dwChannel_ID); + } + + m_pCounters.Clear(TRUE); + + if (m_pClient) + { + m_pClient->Release(); + m_pClient = NULL; + } + + if (m_pChunks) + { + delete [] m_pChunks; + m_pChunks = NULL; + } + + + LOCK_DESTROY(m_sCS); +}// ~CP7Telemetry + + +//////////////////////////////////////////////////////////////////////////////// +// Is_Initialized +tBOOL CP7Telemetry::Is_Initialized() +{ + return m_bInitialized; +}// Is_Initialized + + +//////////////////////////////////////////////////////////////////////////////// +// On_Init +void CP7Telemetry::On_Init(sP7C_Channel_Info *i_pInfo) +{ + if (i_pInfo) + { + m_dwChannel_ID = i_pInfo->dwID; + } +}// On_Init + + +//////////////////////////////////////////////////////////////////////////////// +// On_Receive +void CP7Telemetry::On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian) +{ + UNUSED_ARG(i_dwChannel); + UNUSED_ARG(i_bBigEndian); + + LOCK_ENTER(m_sCS); + + if ( (i_pBuffer) + && (i_dwSize >= sizeof(sP7Ext_Header)) + ) + { + sP7Ext_Raw l_sHeader = *(sP7Ext_Raw*)i_pBuffer; + + if (EP7USER_TYPE_TELEMETRY_V2 == GET_EXT_HEADER_TYPE(l_sHeader)) + { + if (EP7TEL_TYPE_ENABLE == GET_EXT_HEADER_SUBTYPE(l_sHeader)) + { + sP7Tel_Enable_v2 *l_pEnable = (sP7Tel_Enable_v2*)i_pBuffer; + + if (m_pCounters[l_pEnable->wID]) + { + m_pCounters[l_pEnable->wID]->Enable(l_pEnable->bOn); + + if (m_sConf.pEnable_Callback) + { + m_sConf.pEnable_Callback(m_sConf.pContext, l_pEnable->wID, l_pEnable->bOn); + } + } + } + else if (EP7TEL_TYPE_DELETE == GET_EXT_HEADER_SUBTYPE(l_sHeader)) + { + Flush(); + m_bActive = FALSE; + } + } + } + + LOCK_EXIT(m_sCS); +}// On_Receive + + +//////////////////////////////////////////////////////////////////////////////// +// On_Status +void CP7Telemetry::On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus) +{ + UNUSED_ARG(i_dwChannel); + + LOCK_ENTER(m_sCS); + + if (i_pStatus) + { + m_sStatus = *i_pStatus; + + if (m_sConf.pConnect_Callback) + { + m_sConf.pConnect_Callback(m_sConf.pContext, m_sStatus.bConnected); + } + + //if connection was established - sent counters description + if (m_sStatus.bConnected) + { + if (m_bOnConnect_Thread) + { + m_cOnConnect_Event.Set(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); + CThShell::Close(m_hOnConnect_Thread, 1000); + m_hOnConnect_Thread = 0; + m_bOnConnect_Thread = FALSE; + } + + m_bIsHeaderDelivered = FALSE; + + pAList_Cell l_pEl = NULL; + while ((l_pEl = m_pCounters.Get_Next(l_pEl))) + { + CP7Tel_Counter *l_pCounter = m_pCounters.Get_Data(l_pEl); + if (l_pCounter) + { + l_pCounter->m_bDelivered = FALSE; + } + } + + m_cOnConnect_Event.Clr(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); + if (CThShell::Create(&Static_OnConnect_Routine, + this, + &m_hOnConnect_Thread, + TM("P7:Tel:OnConnect") + ) + ) + { + m_bOnConnect_Thread = TRUE; + } + } + else + { + m_bIsHeaderDelivered = FALSE; + if (m_bOnConnect_Thread) + { + m_cOnConnect_Event.Set(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); + CThShell::Close(m_hOnConnect_Thread, 1000); + m_hOnConnect_Thread = 0; + m_bOnConnect_Thread = FALSE; + } + + m_cOnConnect_Event.Clr(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); + + pAList_Cell l_pEl = NULL; + while ((l_pEl = m_pCounters.Get_Next(l_pEl))) + { + CP7Tel_Counter *l_pCounter = m_pCounters.Get_Data(l_pEl); + if (l_pCounter) + { + l_pCounter->m_bDelivered = FALSE; + } + } + } + } + + LOCK_EXIT(m_sCS); +}// On_Status + + +//////////////////////////////////////////////////////////////////////////////// +// On_Flush - external call +void CP7Telemetry::On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash) +{ + UNUSED_ARG(i_dwChannel); + + LOCK_ENTER(m_sCS); + + if ( (io_pCrash) + && (TRUE == *io_pCrash) + && (m_bActive) + ) + { + //nothing special for crash event + } + + Flush(); + + LOCK_EXIT(m_sCS); +}// On_Flush + + +//////////////////////////////////////////////////////////////////////////////// +// Create, i_pName is case sensitive and should be unique +tBOOL CP7Telemetry::Create(const tXCHAR *i_pName, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + tBOOL i_bOn, + tUINT16 *o_pID + ) +{ + tBOOL l_bReturn = FALSE; + sCounterMap *l_pMap = NULL; + tUINT32 l_uiId = 0; + CP7Tel_Counter *l_pCounter = NULL; + tUINT32 l_uHash = 0; + + if ( (FALSE == m_bActive) + || (NULL == i_pName) + || (NULL == o_pID) + ) + { + return FALSE; + } + + LOCK_ENTER(m_sCS); + + *o_pID = P7TELEMETRY_INVALID_ID_V2; + + l_uHash = CP7Tel_Counter::Get_Hash(i_pName); + + //////////////////////////////////////////////////////////////////////////// + //find by name already existing counter + l_pMap = m_cCounters_Map.Find(l_uHash); + if (l_pMap) + { + l_pCounter = l_pMap->pCounter; + while (l_pCounter) + { + if (l_pCounter->Has_Name(i_pName)) + { + //found, and all parameters are the same ... + if ( (l_pCounter->m_pHeader->dbMin == i_dbMin) + && (l_pCounter->m_pHeader->dbMax == i_dbMax) + && (l_pCounter->m_pHeader->dbAlarmMin == i_dbAlarmMin) + && (l_pCounter->m_pHeader->dbAlarmMax == i_dbAlarmMax) + ) + { + *o_pID = l_pCounter->m_pHeader->wID; + l_bReturn = TRUE; + goto l_lblExit; + } + else //name is equal, but some additional parameters are different + { + goto l_lblExit; + } + } + l_pCounter = l_pCounter->pTreeNext; + } + } + + l_pCounter = NULL; + + + if (P7TELEMETRY_INVALID_ID_V2 <= m_pCounters.Count()) + { + goto l_lblExit; + } + + l_uiId = m_pCounters.Count(); + l_pCounter = new CP7Tel_Counter((tUINT16)l_uiId, + i_bOn, + i_dbMin, + i_dbAlarmMin, + i_dbMax, + i_dbAlarmMax, + i_pName, + l_uHash + ); + + if ( (NULL == l_pCounter) + || (FALSE == l_pCounter->Is_Initialized()) + ) + { + if (l_pCounter) + { + delete l_pCounter; + l_pCounter = NULL; + } + + goto l_lblExit; + } + + if (l_pMap) + { + l_pCounter->pTreeNext = l_pMap->pCounter; + l_pMap->pCounter = l_pCounter; + } + else + { + m_cCounters_Map.Push(new sCounterMap(l_pCounter), l_uHash); + } + + if (m_sStatus.bConnected) + { + sP7C_Data_Chunk *l_pChunk = m_pChunks; + tBOOL l_bHeader = FALSE; + tUINT32 l_dwSize = 0; + + //connection was lost, we need to resend initial data + if (!m_bIsHeaderDelivered) + { + l_bHeader = TRUE; + l_pChunk->dwSize = sizeof(m_sHeader_Info); + l_pChunk->pData = &m_sHeader_Info; + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + + l_pChunk->dwSize = sizeof(m_sHeader_Utc); + l_pChunk->pData = &m_sHeader_Utc; + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + } + + l_pChunk->pData = l_pCounter->m_pHeader; + l_pChunk->dwSize = GET_EXT_HEADER_SIZE(l_pCounter->m_pHeader->sCommonRaw);//m_pCounters[m_dwUsed]->m_sCounter.sCommon.dwSize; + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + + if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, m_pChunks, (tUINT32)(l_pChunk - m_pChunks), l_dwSize)) + { + l_pCounter->m_bDelivered = TRUE; + if (l_bHeader) + { + m_bIsHeaderDelivered = TRUE; + } + } + } + + l_bReturn = TRUE; + *o_pID = (tUINT16)l_uiId; + m_pCounters.Add_After(m_pCounters.Get_Last(), l_pCounter); + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; +} //Create + + +//////////////////////////////////////////////////////////////////////////////// +// Find, i_pName is case sensitive +tBOOL CP7Telemetry::Find(const tXCHAR *i_pName, tUINT16 *o_pID) +{ + sCounterMap *l_pMap = NULL; + tBOOL l_bReturn = FALSE; + + if (o_pID) + { + *o_pID = P7TELEMETRY_INVALID_ID_V2; + } + else + { + return FALSE; + } + + if ( (FALSE == m_bActive) + || (NULL == i_pName) + ) + { + return FALSE; + } + + LOCK_ENTER(m_sCS); + l_pMap = m_cCounters_Map.Find(CP7Tel_Counter::Get_Hash(i_pName)); + if (l_pMap) + { + CP7Tel_Counter *l_pCounter = l_pMap->pCounter; + while (l_pCounter) + { + if (l_pCounter->Has_Name(i_pName)) + { + *o_pID = l_pCounter->m_pHeader->wID; + l_bReturn = TRUE; + break; + } + l_pCounter = l_pCounter->pTreeNext; + } + } + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Find + + +//////////////////////////////////////////////////////////////////////////////// +// Add +tBOOL CP7Telemetry::Add(tUINT16 i_bID, tDOUBLE i_dbValue) +{ + tBOOL l_bReturn = TRUE; + tUINT32 l_dwSize = 0; + tUINT8 l_bReset = 0; + CP7Tel_Counter *l_pCounter; //will be initialized lated + sP7C_Data_Chunk *l_pChunk; //will be initialized lated + + if (P7TELEMETRY_INVALID_ID_V2 == i_bID) + { + return FALSE; + } + + LOCK_ENTER(m_sCS); + + l_pCounter = m_pCounters[i_bID]; + + //////////////////////////////////////////////////////////////////////////// + //check ID + if ( (NULL == l_pCounter) + || (FALSE == m_bActive) + || (FALSE == m_sStatus.bConnected) + || (!l_pCounter->m_pHeader->bOn) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_pChunk = m_pChunks; + + //connection was lost, we need to resend initial data + if (!m_bIsHeaderDelivered) + { + l_bReset |= RESET_FLAG_HEADER; + l_pChunk->dwSize = sizeof(m_sHeader_Info); + l_pChunk->pData = &m_sHeader_Info; + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + + l_pChunk->dwSize = sizeof(m_sHeader_Utc); + l_pChunk->pData = &m_sHeader_Utc; + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + } + + //counters descriptions have to send again + if (!l_pCounter->m_bDelivered) + { + l_bReset |= RESET_FLAG_COUNTER; + l_pChunk->pData = l_pCounter->m_pHeader; + l_pChunk->dwSize = GET_EXT_HEADER_SIZE(l_pCounter->m_pHeader->sCommonRaw);//(*l_pIter)->m_sCounter.sCommon.dwSize; + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + } + + m_sValue.wID = i_bID; + m_sValue.dbValue = i_dbValue; + m_sValue.wSeqN = l_pCounter->m_wSeqN ++; + + if (! m_sConf.pTimestamp_Callback ) + { + m_sValue.qwTimer = GetPerformanceCounter(); + } + else + { + m_sValue.qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + + l_pChunk->pData = &m_sValue; + l_pChunk->dwSize = GET_EXT_HEADER_SIZE(m_sValue.sCommonRaw);//m_sValue.sCommon.dwSize; + l_dwSize += l_pChunk->dwSize; + + l_pChunk ++; + + if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + m_pChunks, + (tUINT32)(l_pChunk - m_pChunks), + l_dwSize + ) + ) + { + if (l_bReset & RESET_FLAG_HEADER) + { + m_bIsHeaderDelivered = TRUE; + } + if (l_bReset & RESET_FLAG_COUNTER) + { + l_pCounter->m_bDelivered = TRUE; + } + } + else + { + l_bReturn = FALSE; + } + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Add + + +//////////////////////////////////////////////////////////////////////////////// +// Set_Enable +tBOOL CP7Telemetry::Set_Enable(tUINT16 i_wID, tBOOL i_bEnable) +{ + tBOOL l_bReturn = FALSE; + + if (!m_bInitialized) + { + return l_bReturn; + } + + LOCK_ENTER(m_sCS); + if (m_bActive) + { + CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; + if (l_pCounter) + { + l_bReturn = TRUE; + l_pCounter->m_pHeader->bOn = (tUINT16)i_bEnable; + } + } + LOCK_EXIT(m_sCS); + return l_bReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Enable +tBOOL CP7Telemetry::Get_Enable(tUINT16 i_wID) +{ + tBOOL l_bReturn = FALSE; + if (!m_bInitialized) + { + return l_bReturn; + } + + LOCK_ENTER(m_sCS); + CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; + if (l_pCounter) + { + l_bReturn = (tBOOL)l_pCounter->m_pHeader->bOn; + } + LOCK_EXIT(m_sCS); + return l_bReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Min +tDOUBLE CP7Telemetry::Get_Min(tUINT16 i_wID) +{ + tDOUBLE l_dbReturn = 0.0; + if (!m_bInitialized) + { + return l_dbReturn; + } + + LOCK_ENTER(m_sCS); + CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; + if (l_pCounter) + { + l_dbReturn = l_pCounter->m_pHeader->dbMin; + } + LOCK_EXIT(m_sCS); + return l_dbReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Max +tDOUBLE CP7Telemetry::Get_Max(tUINT16 i_wID) +{ + tDOUBLE l_dbReturn = 0.0; + if (!m_bInitialized) + { + return l_dbReturn; + } + + LOCK_ENTER(m_sCS); + CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; + if (l_pCounter) + { + l_dbReturn = l_pCounter->m_pHeader->dbMax; + } + LOCK_EXIT(m_sCS); + return l_dbReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Name +const tXCHAR *CP7Telemetry::Get_Name(tUINT16 i_wID) +{ + const tXCHAR *l_pReturn = NULL; + if (!m_bInitialized) + { + return l_pReturn; + } + + LOCK_ENTER(m_sCS); + CP7Tel_Counter *l_pCounter = m_pCounters[i_wID]; + if (l_pCounter) + { + l_pReturn = l_pCounter->m_pName; + } + LOCK_EXIT(m_sCS); + return l_pReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Count +tUINT16 CP7Telemetry::Get_Count() +{ + tUINT16 l_wReturn = 0; + if (!m_bInitialized) + { + return l_wReturn; + } + + LOCK_ENTER(m_sCS); + l_wReturn = m_pCounters.Count(); + LOCK_EXIT(m_sCS); + return l_wReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Share +tBOOL CP7Telemetry::Share(const tXCHAR *i_pName) +{ + tBOOL l_bReturn = FALSE; + + LOCK_ENTER(m_sCS); + if (NULL == m_hShared) + { + tUINT32 l_dwLen1 = PStrLen(TELEMETRY_SHARED_PREFIX); + tUINT32 l_dwLen2 = PStrLen(i_pName); + tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); + CShared::hSem l_hSem = SHARED_SEM_NULL; + + if (l_pName) + { + sObjShared l_stShared = {}; + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + tBOOL l_bCreate = TRUE; + + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + + PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, TELEMETRY_SHARED_PREFIX); + PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); + + //JOURNAL_WARNING(m_pLog, TM("Shared memory {%s} registration error"), l_pName); + if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) + { + l_bCreate = FALSE; //it is already existing + + if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) + { + if ( (l_stShared.uProcTimeHi != l_uTimeHi) + || (l_stShared.uProcTimeLo != l_uTimeLo) + ) + { + //JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp error, prev. session crashed or forget to release P7 objects?")); + CShared::UnLink(l_pName); + l_bCreate = TRUE; + } + } + + CShared::UnLock(l_hSem); + } + + if (l_bCreate) + { + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + l_stShared.pPointer = static_cast(this); + l_stShared.uProcTimeHi = l_uTimeHi; + l_stShared.uProcTimeLo = l_uTimeLo; + + l_bReturn = CShared::Create(&m_hShared, l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared)); + } + + free(l_pName); + l_pName = NULL; + } + + } + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Share + + +//////////////////////////////////////////////////////////////////////////////// +// On_Flush - internal call +void CP7Telemetry::Flush() +{ + if (FALSE == m_bActive) + { + return; + } + + m_bActive = FALSE; + + //inform server about channel closing, I didn't check status, just + //sending data + if (m_bIsHeaderDelivered) + { + sP7Ext_Raw l_sHeader; + INIT_EXT_HEADER(l_sHeader, EP7USER_TYPE_TELEMETRY_V2, EP7TEL_TYPE_CLOSE, sizeof(sP7Ext_Raw)); + sP7C_Data_Chunk l_sChunk = {&l_sHeader, sizeof(sP7Ext_Raw)}; + m_pClient->Sent(m_dwChannel_ID, &l_sChunk, 1, l_sChunk.dwSize); + } +}// On_Flush + + +//////////////////////////////////////////////////////////////////////////////// +// OnConnect_Routine +void CP7Telemetry::OnConnect_Routine() +{ + tUINT32 l_uTimeOut = 0; + pAList_Cell l_pCounterEl = NULL; + tBOOL l_bExit = FALSE; + CP7Tel_Counter * l_pCounter = NULL; + sP7C_Data_Chunk l_stChunk; + + while (FALSE == l_bExit) + { + if (TELEMETRY_ON_CONNECT_EXIT_SIGNAL == m_cOnConnect_Event.Wait(l_uTimeOut)) + { + break; + } + + if (LOCK_TRY(m_sCS)) + { + if (!m_bIsHeaderDelivered) + { + sP7C_Data_Chunk l_stChunk[2]; + l_stChunk[0].dwSize = sizeof(m_sHeader_Info); + l_stChunk[0].pData = &m_sHeader_Info; + + l_stChunk[1].dwSize = sizeof(m_sHeader_Utc); + l_stChunk[1].pData = &m_sHeader_Utc; + + if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + l_stChunk, + LENGTH(l_stChunk), + l_stChunk[0].dwSize + l_stChunk[1].dwSize + ) + ) + { + m_bIsHeaderDelivered = TRUE; + } + } + + if (m_bIsHeaderDelivered) + { + tBOOL l_bDelivering = TRUE; + + if (!l_pCounterEl) + { + l_pCounterEl = m_pCounters.Get_First(); + } + + while ( (l_pCounterEl) + && (l_bDelivering) + ) + { + l_pCounter = m_pCounters.Get_Data(l_pCounterEl); + if (l_pCounter) + { + if (!l_pCounter->m_bDelivered) + { + l_stChunk.pData = l_pCounter->m_pHeader; + l_stChunk.dwSize = GET_EXT_HEADER_SIZE(l_pCounter->m_pHeader->sCommonRaw); + + if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, &l_stChunk, 1, l_stChunk.dwSize)) + { + l_pCounter->m_bDelivered = TRUE; + l_pCounterEl = m_pCounters.Get_Next(l_pCounterEl); + l_uTimeOut = 0; + } + else + { + l_uTimeOut = 5; + l_bDelivering = FALSE; + } + } + else + { + l_pCounterEl = m_pCounters.Get_Next(l_pCounterEl); + } + } + } + + if (!l_pCounterEl) + { + l_bExit = TRUE; + } + } + LOCK_EXIT(m_sCS); + } + } + + m_cOnConnect_Event.Clr(TELEMETRY_ON_CONNECT_EXIT_SIGNAL); +} + + diff --git a/p7lib/Sources/Telemetry.h b/p7lib/Sources/Telemetry.h new file mode 100644 index 0000000..941d2ae --- /dev/null +++ b/p7lib/Sources/Telemetry.h @@ -0,0 +1,223 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This file provide trace functionality / +//////////////////////////////////////////////////////////////////////////////// +#ifndef TELEMETRY_H +#define TELEMETRY_H + + +//////////////////////////////////////////////////////////////////////////////// +//CP7Tel_Counter +class CP7Tel_Counter +{ +private: + tBOOL m_bInitialized; + +public: + tXCHAR *m_pName; + tBOOL m_bDelivered; + sP7Tel_Counter_v2 *m_pHeader; + tUINT16 m_wSeqN; + tUINT32 m_uHash; + CP7Tel_Counter *pTreeNext; + + CP7Tel_Counter(tUINT16 i_wID, + tUINT8 i_bOn, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + const tXCHAR *i_pName, + tUINT32 i_uHash + ); + ~CP7Tel_Counter(); + + static tUINT32 Get_Hash(const tXCHAR *i_pName); + + tBOOL Has_Name(const tXCHAR *i_pName); + tBOOL Is_Initialized(); + void Enable(tUINT16 i_wOn); +};//CP7Tel_Counter + + +//////////////////////////////////////////////////////////////////////////////// +//sCounterMap +struct sCounterMap +{ + CP7Tel_Counter *pCounter; + + sCounterMap(CP7Tel_Counter *i_pCounter) + : pCounter(i_pCounter) + { + } + + ~sCounterMap() + { + pCounter = NULL; + } +};//sCounterMap + + +//////////////////////////////////////////////////////////////////////////////// +//CCounters_Tree +class CCounters_Tree: + public CRBTree +{ +public: + CCounters_Tree() + : CRBTree(16, TRUE) + { + } + +protected: + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(tUINT32 i_uKey, sCounterMap *i_pData) + { + return (i_uKey < i_pData->pCounter->m_uHash) ? TRUE : FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(tUINT32 i_uKey, sCounterMap *i_pData) + { + return (i_uKey == i_pData->pCounter->m_uHash) ? TRUE : FALSE; + } +};//CCounters_Tree + + + +//////////////////////////////////////////////////////////////////////////////// +//CP7Telemetry +class CP7Telemetry + : public IP7_Telemetry +{ + //put volatile variables at the top, to obtain 32 bit alignment. + //Project has 8 bytes alignment by default + tINT32 volatile m_lReference; + + IP7_Client *m_pClient; + tUINT32 m_dwChannel_ID; + + tBOOL m_bInitialized; + + tBOOL m_bActive; + + tLOCK m_sCS; + + sP7Tel_Info m_sHeader_Info; + sP7Tel_Utc_Offs_V2 m_sHeader_Utc; + sP7Tel_Value_v2 m_sValue; + + CCounters_Tree m_cCounters_Map; + CBList m_pCounters; + + tBOOL m_bIsHeaderDelivered; + sP7C_Status m_sStatus; + + sP7C_Data_Chunk *m_pChunks; + tUINT32 m_dwChunks_Max_Count; + + tBOOL m_bIs_Channel; + + CShared::hShared m_hShared; + + stTelemetry_Conf m_sConf; + + CMEvent m_cOnConnect_Event; + tBOOL m_bOnConnect_Thread; + CThShell::tTHREAD m_hOnConnect_Thread; + + +public: + CP7Telemetry(IP7_Client *i_pClient, const tXCHAR *i_pName, const stTelemetry_Conf *i_pConf); + virtual ~CP7Telemetry(); + + tBOOL Is_Initialized(); + + //IP7C_Channel-------------------------------------------------------------- + IP7C_Channel::eType Get_Type() { return IP7C_Channel::eTelemetry; } + void On_Init(sP7C_Channel_Info *i_pInfo); + void On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian); + void On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus); + void On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash); + + virtual tINT32 Add_Ref() + { + return ATOMIC_INC(&m_lReference); + } + + virtual tINT32 Release() + { + tINT32 l_lResult = ATOMIC_DEC(&m_lReference); + if ( 0 >= l_lResult ) + { + delete this; + } + + return l_lResult; + } + + //IP7_Telemetry------------------------------------------------------------- + virtual tBOOL Create(const tXCHAR *i_pName, + tDOUBLE i_dbMin, + tDOUBLE i_dbAlarmMin, + tDOUBLE i_dbMax, + tDOUBLE i_dbAlarmMax, + tBOOL i_bOn, + tUINT16 *o_pID + ); + + virtual tBOOL Find(const tXCHAR *i_pName, tUINT16 *o_pID); + virtual tBOOL Add(tUINT16 i_bID, tDOUBLE i_llValue); + virtual tBOOL Set_Enable(tUINT16 i_wID, tBOOL i_bEnable); + virtual tBOOL Get_Enable(tUINT16 i_wID); + virtual tDOUBLE Get_Min(tUINT16 i_wID); + virtual tDOUBLE Get_Max(tUINT16 i_wID); + virtual const tXCHAR *Get_Name(tUINT16 i_wID); + virtual tUINT16 Get_Count(); + + virtual tBOOL Share(const tXCHAR *i_pName); + + + +private: + void Flush(); + + static THSHELL_RET_TYPE THSHELL_CALL_TYPE Static_OnConnect_Routine(void *i_pContext) + { + CP7Telemetry *l_pRoutine = static_cast(i_pContext); + if (l_pRoutine) + { + l_pRoutine->OnConnect_Routine(); + } + + CThShell::Cleanup(); + return THSHELL_RET_OK; + } + + void OnConnect_Routine(); +};//CP7Telemetry + +#endif //TELEMETRY_H diff --git a/p7lib/Sources/Trace.cpp b/p7lib/Sources/Trace.cpp new file mode 100644 index 0000000..d28b43e --- /dev/null +++ b/p7lib/Sources/Trace.cpp @@ -0,0 +1,2945 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This file provide trace functionality / +//////////////////////////////////////////////////////////////////////////////// +//Printf Type Field Characters: / +// http://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx / +//Printf Type Field Characters: / +// http://msdn.microsoft.com/en-us/library/hf4y5e3w(v=vs.100).aspx / +//Size and Distance Specification / +// http://msdn.microsoft.com/en-us/library/tcxf1dw6(v=vs.100).aspx / +//////////////////////////////////////////////////////////////////////////////// +#include "CommonClient.h" +#include "Trace.h" +#include +#include + +#define RESET_UNDEFINED (0xFFFFFFFFUL) +#define RESET_FLAG_CHANNEL (0x1) +#define RESET_FLAG_TRACE (0x2) + +#define FORMAT_CRASH_MESSAGE TM("Abnormal program termination, stack:") +#define FORMAT_STACK_MESSAGE TM(" ->[%02d] (0x%016I64X) %s, line %d") +#define FORMAT_FILE_UNKNOWN "-------" +#define FORMAT_FUNC_UNKNOWN "-------" +#define TRACE_SHARED_PREFIX TM("Trc_") +#define TRACE_EXTRA_CHUNKS (5) + +#if !defined(UINTMAX_MAX) + typedef uint64_t uintmax_t; + #define UINTMAX_MAX 0xffffffffffffffffU +#endif + +#if !defined(INTMAX_MAX) + typedef int64_t intmax_t; + #define INTMAX_MIN (-0x7fffffffffffffff - 1) + #define INTMAX_MAX 0x7fffffffffffffff +#endif + +#define ADD_ARG(i_bType, i_bSize, oResult)\ +{\ + oResult = FALSE;\ + if (m_dwArgs_Count < l_dwArgs_Max)\ + {\ + l_pArgs[m_dwArgs_Count].bType = i_bType;\ + l_pArgs[m_dwArgs_Count].bSize = i_bSize;\ + m_dwArgs_Count ++;\ + oResult = TRUE;\ + }\ + else if ( m_dwArgs_Count >= l_dwArgs_Max )\ + {\ + tUINT32 l_dwLength = m_dwArgs_Count + 16;\ + sP7Trace_Arg *l_pTMP = (sP7Trace_Arg*)i_rMemory.Reuse(CMemoryManager::eArguments,\ + l_dwLength * sizeof(sP7Trace_Arg)\ + );\ + if (l_pTMP)\ + {\ + l_pArgs = l_pTMP;\ + l_dwArgs_Max = l_dwLength;\ + l_pArgs[m_dwArgs_Count].bType = i_bType;\ + l_pArgs[m_dwArgs_Count].bSize = i_bSize;\ + m_dwArgs_Count ++;\ + oResult = TRUE;\ + }\ + }\ +} + +extern "C" +{ + +//////////////////////////////////////////////////////////////////////////////// +//P7_Create_Client +P7_EXPORT IP7_Trace * __cdecl P7_Create_Trace(IP7_Client *i_pClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf + ) +{ + //Check parameters + if (i_pConf) + { + if ( ( (!i_pConf->qwTimestamp_Frequency) + && (i_pConf->pTimestamp_Callback) + ) + || ( (i_pConf->qwTimestamp_Frequency) + && (!i_pConf->pTimestamp_Callback) + ) + ) + { + return NULL; + } + } + + CP7Trace *l_pReturn = new CP7Trace(i_pClient, i_pName, i_pConf); + + //if not initialized - remove + if ( (l_pReturn) + && (TRUE != l_pReturn->Is_Initialized()) + ) + { + l_pReturn->Release(); + l_pReturn = NULL; + } + + return static_cast(l_pReturn); +}//P7_Create_Client + + +//////////////////////////////////////////////////////////////////////////////// +//P7_Get_Shared_Trace +P7_EXPORT IP7_Trace * __cdecl P7_Get_Shared_Trace(const tXCHAR *i_pName) +{ + size_t l_szPadding = 16; + IP7_Trace *l_pReturn = NULL; + tUINT32 l_dwLen1 = PStrLen(TRACE_SHARED_PREFIX); + tUINT32 l_dwLen2 = PStrLen(i_pName); + tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + l_szPadding)); + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + sObjShared l_stShared = {}; + CShared::hSem l_hSem = SHARED_SEM_NULL; + + + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + + if (l_pName) + { + PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + l_szPadding, TRACE_SHARED_PREFIX); + PStrCpy(l_pName + l_dwLen1, l_dwLen2 + l_szPadding, i_pName); + + if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) + { + if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) + { + if ( (l_stShared.uProcTimeHi == l_uTimeHi) + && (l_stShared.uProcTimeLo == l_uTimeLo) + ) + { + l_pReturn = static_cast(l_stShared.pPointer); + if (l_pReturn) + { + l_pReturn->Add_Ref(); + } + } + else + { + CShared::UnLink(l_pName); + } + } + + CShared::UnLock(l_hSem); + } + + free(l_pName); + l_pName = NULL; + } + + return l_pReturn; +}//P7_Get_Shared_Trace + +} //extern "C" + + +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +enum ePrefix_Type +{ + EPREFIX_TYPE_I64 = 0, + EPREFIX_TYPE_I32 , + EPREFIX_TYPE_LL , + EPREFIX_TYPE_L , + EPREFIX_TYPE_HH , + EPREFIX_TYPE_H , + EPREFIX_TYPE_I , + EPREFIX_TYPE_W , + EPREFIX_TYPE_J , + EPREFIX_TYPE_UNKNOWN +}; + +struct sPrefix_Desc +{ + const tXCHAR *pPrefix; + tUINT32 dwLen; + ePrefix_Type eType; +}; + + + +//the order of strings IS VERY important, because we will search for first match +static const sPrefix_Desc g_pPrefixes[] = { {TM("I64"), 3, EPREFIX_TYPE_I64 }, + {TM("I32"), 3, EPREFIX_TYPE_I32 }, + {TM("ll"), 2, EPREFIX_TYPE_LL }, + {TM("hh"), 2, EPREFIX_TYPE_HH }, + {TM("h"), 1, EPREFIX_TYPE_H }, + {TM("l"), 1, EPREFIX_TYPE_L }, + {TM("I"), 1, EPREFIX_TYPE_I }, + {TM("z"), 1, EPREFIX_TYPE_I }, + {TM("t"), 1, EPREFIX_TYPE_I }, + {TM("w"), 1, EPREFIX_TYPE_W }, + {TM("j"), 1, EPREFIX_TYPE_J }, + {TM("?"), 0, EPREFIX_TYPE_UNKNOWN} + }; + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Prefix +const sPrefix_Desc *Get_Prefix(const tXCHAR *i_pFormat) +{ + const sPrefix_Desc *l_pPrefix = &g_pPrefixes[0]; + const sPrefix_Desc *l_pReturn = NULL; + + while (l_pPrefix->dwLen) + { + if (0 == PStrNCmp(i_pFormat, l_pPrefix->pPrefix, l_pPrefix->dwLen)) + { + l_pReturn = l_pPrefix; + break; + } + + l_pPrefix ++; + } + + return l_pReturn; +}// Get_Prefix + + + +//////////////////////////////////////////////////////////////////////////////// +// CP7Trace_Desc +CP7Trace_Desc::CP7Trace_Desc(CMemoryManager &i_rMemory, + tUINT16 i_wID, + tUINT16 i_wLine, + tUINT16 i_wModuleID, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_pFormat, + tKeyType i_pKeys[P7TRACE_KEY_LENGTH], + tUINT32 i_dwFlags + ) + : m_wID(i_wID) + , m_wModuleID(i_wModuleID) + , m_dwResets(RESET_UNDEFINED) + , m_dwSize(0) + , m_pBuffer(NULL) + + , m_pBlocks(NULL) + , m_dwBlocks_Count(0) + , m_pArgs(NULL) + , m_dwArgs_Count(0) + + , m_bInitialized(TRUE) +{ + UNUSED_ARG(i_dwFlags); + + tUINT32 l_dwFile_Size = 0; + tUINT32 l_dwFunc_Size = 0; + tUINT32 l_dwForm_Size = 0; + const tXCHAR *l_pFormat = *i_pFormat; + sP7Trace_Arg *l_pArgs = NULL; + tUINT32 l_dwArgs_Max = 0; + tUINT8 l_bSize = 0; + + m_bInitialized = (NULL != l_pFormat); + + m_pKey[0] = i_pKeys[0]; + m_pKey[1] = i_pKeys[1]; + + if (m_bInitialized) + { + ePrefix_Type l_ePrefix = EPREFIX_TYPE_UNKNOWN; + const tXCHAR *l_pIterator = l_pFormat; + tBOOL l_bPercent = FALSE; + + while ( (*l_pIterator) + && (m_bInitialized) + ) + { + if (FALSE == l_bPercent) + { + if (TM('%') == (*l_pIterator)) + { + //we can get "%%" in this case we should ignore "%" + l_bPercent = ! l_bPercent;//TRUE; + l_ePrefix = EPREFIX_TYPE_UNKNOWN; + l_bSize = 0; + } + } + else + { + switch (*l_pIterator) + { + case TM('*'): + { + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + l_bSize = 1; + break; + } + case TM('I'): + case TM('l'): + case TM('h'): + case TM('w'): + case TM('z'): + case TM('j'): + case TM('t'): + { + const sPrefix_Desc *l_pPrefix = Get_Prefix(l_pIterator); + if (l_pPrefix) + { + l_ePrefix = l_pPrefix->eType; + + if (1 < l_pPrefix->dwLen) + { + l_pIterator += (l_pPrefix->dwLen - 1); + } + } + break; + } + case TM('d'): + case TM('b'): + case TM('i'): + case TM('o'): + case TM('u'): + case TM('x'): + case TM('X'): + { + if (EPREFIX_TYPE_UNKNOWN == l_ePrefix) + { + //4 bytes integer + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + } + else if ( (EPREFIX_TYPE_LL == l_ePrefix) + || (EPREFIX_TYPE_I64 == l_ePrefix) + ) + { + //8 bytes integer + ADD_ARG(P7TRACE_ARG_TYPE_INT64, SIZE_OF_ARG(tUINT64), m_bInitialized); + } + else if (EPREFIX_TYPE_H == l_ePrefix) + { + //2 bytes integer + ADD_ARG(P7TRACE_ARG_TYPE_INT16, SIZE_OF_ARG(tUINT16), m_bInitialized); + } + else if (EPREFIX_TYPE_HH == l_ePrefix) + { + //1 bytes integer + ADD_ARG(P7TRACE_ARG_TYPE_INT8, SIZE_OF_ARG(tUINT8), m_bInitialized); + } + else if (EPREFIX_TYPE_L == l_ePrefix) + { + #if defined(__linux__) + #ifdef GTX64 + ADD_ARG(P7TRACE_ARG_TYPE_INT64, SIZE_OF_ARG(tUINT64), m_bInitialized); + #else + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + #endif + #else + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + #endif + } + else if (EPREFIX_TYPE_I32 == l_ePrefix) + { + //4 bytes integer + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + } + else if (EPREFIX_TYPE_I == l_ePrefix) + { + #ifdef GTX64 + ADD_ARG(P7TRACE_ARG_TYPE_INT64, SIZE_OF_ARG(tUINT64), m_bInitialized); + #else + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + #endif + } + else if (EPREFIX_TYPE_J == l_ePrefix) + { + //8 bytes integer for most of the platforms, truncate for others + ADD_ARG(P7TRACE_ARG_TYPE_INTMAX, SIZE_OF_ARG(uintmax_t), m_bInitialized); + } + else //by default + { + //4 bytes integer + ADD_ARG(P7TRACE_ARG_TYPE_INT32, SIZE_OF_ARG(tUINT32), m_bInitialized); + } + + l_bPercent = FALSE; + break; + } + case TM('s'): + case TM('S'): + { + if (EPREFIX_TYPE_H == l_ePrefix) + { + ADD_ARG(P7TRACE_ARG_TYPE_STRA, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*) + } +#ifdef UTF8_ENCODING //%S NOT PORTABLE, DO NOT USE IT!, use %ls or %hs + else if (TM('S') == (*l_pIterator)) + { + ADD_ARG(P7TRACE_ARG_TYPE_USTR32, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*) + } +#else + else if (TM('S') == (*l_pIterator)) + { + ADD_ARG(P7TRACE_ARG_TYPE_STRA, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*) + } +#endif + else if (EPREFIX_TYPE_L == l_ePrefix) + { +#ifdef UTF8_ENCODING + ADD_ARG(P7TRACE_ARG_TYPE_USTR32, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*) +#else + ADD_ARG(P7TRACE_ARG_TYPE_USTR16, l_bSize, m_bInitialized); //SIZE_OF_ARG(wchar_t*) +#endif + } + else + { +#ifdef UTF8_ENCODING + ADD_ARG(P7TRACE_ARG_TYPE_USTR8, l_bSize, m_bInitialized); //SIZE_OF_ARG(char*) +#else + ADD_ARG(P7TRACE_ARG_TYPE_USTR16, l_bSize, m_bInitialized); //SIZE_OF_ARG(wchar_t*) +#endif + } + + l_bPercent = FALSE; + break; + } + //case TM('n'): ignored, not supported + case TM('p'): + { + ADD_ARG(P7TRACE_ARG_TYPE_PVOID, SIZE_OF_ARG(void*), m_bInitialized); + l_bPercent = FALSE; + break; + } + case TM('e'): + case TM('E'): + case TM('f'): + case TM('g'): + case TM('G'): + case TM('a'): + case TM('A'): + { + //8 bytes double + ADD_ARG(P7TRACE_ARG_TYPE_DOUBLE, SIZE_OF_ARG(tDOUBLE), m_bInitialized); + l_bPercent = FALSE; + break; + } + case TM('c'): + case TM('C'): + { + if (EPREFIX_TYPE_H == l_ePrefix) + { + //1 bytes character + ADD_ARG(P7TRACE_ARG_TYPE_CHAR, SIZE_OF_ARG(char), m_bInitialized); + } + else if (EPREFIX_TYPE_L == l_ePrefix) + { +#ifdef UTF8_ENCODING + ADD_ARG(P7TRACE_ARG_TYPE_CHAR32, SIZE_OF_ARG(wchar_t), m_bInitialized); +#else + ADD_ARG(P7TRACE_ARG_TYPE_CHAR16, SIZE_OF_ARG(wchar_t), m_bInitialized); +#endif + } + else if (TM('c') == (*l_pIterator)) + { +#ifdef UTF8_ENCODING + ADD_ARG(P7TRACE_ARG_TYPE_CHAR, SIZE_OF_ARG(char), m_bInitialized); +#else + ADD_ARG(P7TRACE_ARG_TYPE_CHAR16, SIZE_OF_ARG(wchar_t), m_bInitialized); +#endif + } + else + { + //1 bytes character + ADD_ARG(P7TRACE_ARG_TYPE_CHAR, SIZE_OF_ARG(char), m_bInitialized); + } + + l_bPercent = FALSE; + break; + } + case TM('%'): + { + l_bPercent = FALSE; + break; + } + } //switch (*l_pIterator) + + if ( (TM('0') <= (*l_pIterator)) + && (TM('9') >= (*l_pIterator)) + ) + { + l_bSize = 1; + } + } + + l_pIterator ++; + } //while ( (*l_pIterator) + + //if (FALSE == m_bInitialized) + //{ + // m_dwArgs_Count = 0; + // l_pFormat = TM("WRONG TRACE ARGUMENTS !"); + //} + } //if (m_bInitialized) + + if (m_bInitialized) + { + m_dwSize = sizeof(sP7Trace_Format); + + if (l_pArgs) + { + m_dwSize += sizeof(sP7Trace_Arg) * m_dwArgs_Count; + } + + if (i_pFile) + { + l_dwFile_Size += (tUINT32)strlen(i_pFile); + } + l_dwFile_Size ++; //last 0 + + if (i_pFunction) + { + l_dwFunc_Size += (tUINT32)strlen(i_pFunction); + } + l_dwFunc_Size ++; //last 0 + + l_dwForm_Size = (PUStrLen(l_pFormat) + 1) * sizeof(tWCHAR); + m_dwSize += l_dwForm_Size + l_dwFunc_Size + l_dwFile_Size; + + + m_pBuffer = (tUINT8*)i_rMemory.Alloc(m_dwSize); + if (NULL == m_pBuffer) + { + m_bInitialized = FALSE; + } + } + + + //calculate stack blocks max size + if ( (m_bInitialized) + && (l_pArgs) + ) + { + tBOOL l_bCumulative = FALSE; + + //allocate blocks for every variable + m_dwBlocks_Count = 0; + m_pBlocks = (tINT32*)i_rMemory.Alloc(sizeof(tINT32) * (m_dwArgs_Count)); + + if (m_pBlocks) //fill the blocks + { + memset(m_pBlocks, 0, sizeof(tINT32) * m_dwArgs_Count); + l_bCumulative = FALSE; + + for (tUINT32 l_dwI = 0; l_dwI < m_dwArgs_Count; l_dwI++) + { + if (P7TRACE_ARG_TYPE_PVOID >= l_pArgs[l_dwI].bType) //most probable case + { + if (FALSE == l_bCumulative) + { + m_dwBlocks_Count ++; + l_bCumulative = TRUE; + } + + m_pBlocks[m_dwBlocks_Count - 1] += l_pArgs[l_dwI].bSize; + } + else if (P7TRACE_ARG_TYPE_USTR16 == l_pArgs[l_dwI].bType) + { + if (0 == l_pArgs[l_dwI].bSize) + { + m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_USTRING16; + } + else + { + m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_WSTRING_FIX; + l_pArgs[l_dwI].bSize = 0; + } + + m_dwBlocks_Count ++; + l_bCumulative = FALSE; + } + else if ( (P7TRACE_ARG_TYPE_STRA == l_pArgs[l_dwI].bType) + || (P7TRACE_ARG_TYPE_USTR8 == l_pArgs[l_dwI].bType) + ) + { + if (0 == l_pArgs[l_dwI].bSize) + { + m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_ASTRING; + } + else + { + m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_ASTRING_FIX; + l_pArgs[l_dwI].bSize = 0; + } + + m_dwBlocks_Count ++; + l_bCumulative = FALSE; + } + else if (P7TRACE_ARG_TYPE_USTR32 == l_pArgs[l_dwI].bType) + { + if (0 == l_pArgs[l_dwI].bSize) + { + m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_USTRING32; + } + else + { + m_pBlocks[m_dwBlocks_Count] = P7TRACE_ITEM_BLOCK_WSTRING_FIX; + l_pArgs[l_dwI].bSize = 0; + } + + m_dwBlocks_Count ++; + l_bCumulative = FALSE; + } + else + { + if (FALSE == l_bCumulative) + { + m_dwBlocks_Count ++; + l_bCumulative = TRUE; + } + + m_pBlocks[m_dwBlocks_Count - 1] += l_pArgs[l_dwI].bSize; + } + } + } + else + { + m_bInitialized = FALSE; + } + } + + //forming trace format header with all related info + if (m_bInitialized) + { + tUINT32 l_dwOffset = 0; + + sP7Trace_Format *l_pHeader_Desc = (sP7Trace_Format *)(m_pBuffer + l_dwOffset); + + INIT_EXT_HEADER(l_pHeader_Desc->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_DESC, m_dwSize); + //l_pHeader_Desc->sCommon.dwSize = m_dwSize; + //l_pHeader_Desc->sCommon.dwType = EP7USER_TYPE_TRACE; + //l_pHeader_Desc->sCommon.dwSubType = EP7TRACE_TYPE_DESC; + + l_pHeader_Desc->wArgs_Len = (tUINT16)m_dwArgs_Count; + l_pHeader_Desc->wID = i_wID; + l_pHeader_Desc->wLine = i_wLine; + l_pHeader_Desc->wModuleID = i_wModuleID; + l_dwOffset += sizeof(sP7Trace_Format); + + + if (l_pArgs) + { + memcpy(m_pBuffer + l_dwOffset, + l_pArgs, + sizeof(sP7Trace_Arg) * m_dwArgs_Count + ); + m_pArgs = (sP7Trace_Arg*)(m_pBuffer + l_dwOffset); + l_dwOffset += sizeof(sP7Trace_Arg) * m_dwArgs_Count; + } + + //we do not verify address of l_pFormat because we do it before + PUStrCpy((tWCHAR*)(m_pBuffer + l_dwOffset), + (m_dwSize - l_dwOffset) / sizeof(tWCHAR), + l_pFormat + ); + + l_dwOffset += l_dwForm_Size; + + if (i_pFile) + { + memcpy(m_pBuffer + l_dwOffset, i_pFile, l_dwFile_Size); + l_dwOffset += l_dwFile_Size; + } + else + { + m_pBuffer[l_dwOffset ++] = 0; + } + + if (i_pFunction) + { + memcpy(m_pBuffer + l_dwOffset, i_pFunction, l_dwFunc_Size); + l_dwOffset += l_dwFunc_Size; + } + else + { + m_pBuffer[l_dwOffset ++] = 0; + } + } +} // CP7Trace_Desc + + +//////////////////////////////////////////////////////////////////////////////// +// CP7Trace_Desc +CP7Trace_Desc::CP7Trace_Desc(CMemoryManager &i_rMemory, + tUINT16 i_wID, + tUINT16 i_wLine, + tUINT16 i_wModuleID, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + tKeyType i_pKeys[P7TRACE_KEY_LENGTH] + ) + : m_wID(i_wID) + , m_wModuleID(i_wModuleID) + , m_dwResets(RESET_UNDEFINED) + , m_dwSize(0) + , m_pBuffer(NULL) + + , m_pBlocks(NULL) + , m_dwBlocks_Count(0) + + , m_pArgs(NULL) + , m_dwArgs_Count(0) + + , m_bInitialized(TRUE) +{ + const tXCHAR *l_pFormat = TM("%s"); + tUINT32 l_dwFile_Size = 0; + tUINT32 l_dwFunc_Size = 0; + tUINT32 l_dwForm_Size = 0; + char *l_pFile = NULL; + char *l_pFunction = NULL; + sP7Trace_Arg *l_pArgs = NULL; + tUINT32 l_dwArgs_Max = 0; + + if (i_pKeys) + { + m_pKey[0] = i_pKeys[0]; + m_pKey[1] = i_pKeys[1]; + } + else + { + m_pKey[0] = 0; + m_pKey[1] = 0; + } + + if (m_bInitialized) + { + #ifdef UTF8_ENCODING + ADD_ARG(P7TRACE_ARG_TYPE_USTR8, 0, m_bInitialized); //SIZE_OF_ARG(char*) + #else + ADD_ARG(P7TRACE_ARG_TYPE_USTR16, 0, m_bInitialized); //SIZE_OF_ARG(wchar_t*) + #endif + } //if (m_bInitialized) + + if (m_bInitialized) + { + m_dwSize = sizeof(sP7Trace_Format); + + if (l_pArgs) + { + m_dwSize += sizeof(sP7Trace_Arg) * m_dwArgs_Count; + } + + if (i_pFile) + { + l_dwFile_Size = (tUINT32)PStrLen(i_pFile); + + #ifdef UTF8_ENCODING + l_pFile = const_cast(i_pFile); + #else + l_dwFile_Size *= 5; + l_pFile = (char*)i_rMemory.Reuse(CMemoryManager::eFileName, l_dwFile_Size); + l_dwFile_Size = Convert_UTF16_To_UTF8((const tWCHAR *)i_pFile, + l_pFile, + l_dwFile_Size + ); + #endif + } + l_dwFile_Size ++; //last 0 + + if (i_pFunction) + { + l_dwFunc_Size = (tUINT32)PStrLen(i_pFunction); + + #ifdef UTF8_ENCODING + l_pFunction = const_cast(i_pFunction); + #else + l_dwFunc_Size *= 5; + l_pFunction = (char*)i_rMemory.Reuse(CMemoryManager::eFunctionName, l_dwFunc_Size); + l_dwFunc_Size = Convert_UTF16_To_UTF8((const tWCHAR *)i_pFunction, + l_pFunction, + l_dwFunc_Size + ); + #endif + } + l_dwFunc_Size ++; //last 0 + + l_dwForm_Size = (PUStrLen(l_pFormat) + 1) * sizeof(tWCHAR); + m_dwSize += l_dwForm_Size + l_dwFunc_Size + l_dwFile_Size; + + m_pBuffer = (tUINT8*)i_rMemory.Alloc(m_dwSize); + if (NULL == m_pBuffer) + { + m_bInitialized = FALSE; + } + } + + if (m_bInitialized) + { + tUINT32 l_dwOffset = 0; + sP7Trace_Format *l_pHeader_Desc = (sP7Trace_Format *)(m_pBuffer + l_dwOffset); + + INIT_EXT_HEADER(l_pHeader_Desc->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_DESC, m_dwSize); + //l_pHeader_Desc->sCommon.dwSize = m_dwSize; + //l_pHeader_Desc->sCommon.dwType = EP7USER_TYPE_TRACE; + //l_pHeader_Desc->sCommon.dwSubType = EP7TRACE_TYPE_DESC; + + l_pHeader_Desc->wArgs_Len = (tUINT16)m_dwArgs_Count; + l_pHeader_Desc->wID = i_wID; + l_pHeader_Desc->wLine = i_wLine; + l_pHeader_Desc->wModuleID = i_wModuleID; + l_dwOffset += sizeof(sP7Trace_Format); + + if (l_pArgs) + { + memcpy(m_pBuffer + l_dwOffset, + l_pArgs, + sizeof(sP7Trace_Arg) * m_dwArgs_Count + ); + l_dwOffset += sizeof(sP7Trace_Arg) * m_dwArgs_Count; + } + + //I don't verify address of l_pFormat because I did it before + PUStrCpy((tWCHAR*)(m_pBuffer + l_dwOffset), + (m_dwSize - l_dwOffset) / sizeof(tWCHAR), + l_pFormat + ); + + l_dwOffset += l_dwForm_Size; + + if (l_pFile) + { + memcpy(m_pBuffer + l_dwOffset, l_pFile, l_dwFile_Size); + l_dwOffset += l_dwFile_Size; + } + else + { + m_pBuffer[l_dwOffset ++] = 0; + } + + if (l_pFunction) + { + memcpy(m_pBuffer + l_dwOffset, l_pFunction, l_dwFunc_Size); + l_dwOffset += l_dwFunc_Size; + } + else + { + m_pBuffer[l_dwOffset ++] = 0; + } + } + +} // CP7Trace_Desc + + +//////////////////////////////////////////////////////////////////////////////// +// Is_Initialized +tBOOL CP7Trace_Desc::Is_Initialized() +{ + return m_bInitialized; +}// Is_Initialized + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Buffer +tUINT8 *CP7Trace_Desc::Get_Buffer(tUINT32 *o_pSize) +{ + if (NULL != o_pSize) + { + *o_pSize = m_dwSize; + } + return m_pBuffer; +}// Get_Buffer + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Blocks +tINT32 *CP7Trace_Desc::Get_Blocks(tUINT32 *o_pCount) +{ + if (NULL == o_pCount) + { + return NULL; + } + + *o_pCount = m_dwBlocks_Count; + + return m_pBlocks; +}// Get_Blocks + + +//////////////////////////////////////////////////////////////////////////////// +// Set_Resets +void CP7Trace_Desc::Set_Resets(tUINT32 i_dwResets) +{ + m_dwResets = i_dwResets; +}// Set_Resets + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Resets +tUINT32 CP7Trace_Desc::Get_Resets() +{ + return m_dwResets; +}// Get_Resets + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Arguments_Count +tUINT32 CP7Trace_Desc::Get_Arguments_Count() +{ + return m_dwArgs_Count; +}// Get_Arguments_Count + +//////////////////////////////////////////////////////////////////////////////// +// Get_Arguments +const sP7Trace_Arg *CP7Trace_Desc::Get_Arguments(tUINT32 &o_rCount) +{ + o_rCount = m_dwArgs_Count; + return m_pArgs; +}// Get_Arguments + + +//////////////////////////////////////////////////////////////////////////////// +// Is_Equal +GASSERT(P7TRACE_KEY_LENGTH == 2); +tBOOL CP7Trace_Desc::Is_Equal(tKeyType *i_pKey) +{ + return ((i_pKey[0] == m_pKey[0]) && (i_pKey[1] == m_pKey[1])); +}// Is_Equal + + +//////////////////////////////////////////////////////////////////////////////// +// Is_Greater (m_pKey > i_pKey) == TRUE +GASSERT(P7TRACE_KEY_LENGTH == 2); +tBOOL CP7Trace_Desc::Is_Greater(tKeyType *i_pKey) +{ + if (i_pKey[0] < m_pKey[0]) + { + return TRUE; + } + + if ((i_pKey[0] == m_pKey[0]) && (i_pKey[1] < m_pKey[1])) + { + return TRUE; + } + + return FALSE; +}// Is_Greater + + +//////////////////////////////////////////////////////////////////////////////// +// Get_ID +tUINT16 CP7Trace_Desc::Get_ID() +{ + return m_wID; +} //Get_ID + +//////////////////////////////////////////////////////////////////////////////// +// Get_MID +tUINT16 CP7Trace_Desc::Get_MID() +{ + return m_wModuleID; +} // Get_MID + + + +//////////////////////////////////////////////////////////////////////////////// +// CP7Trace +CP7Trace::CP7Trace(IP7_Client *i_pClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf) + : m_lReference(1) + , m_dwSequence(0) + , m_pClient(i_pClient) + , m_dwChannel_ID(0) + , m_wDesc_Tree_ID(P7_TRACE_DESC_HARDCODED_COUNT) + , m_dwLast_ID(0) + , m_bInitialized(TRUE) + , m_bActive(TRUE) + , m_eVerbosity(EP7TRACE_LEVEL_TRACE) + , m_pChk_Head(NULL) + , m_pChk_Tail(NULL) + , m_pChk_Curs(NULL) + , m_dwChk_Count(0) + , m_dwChk_Size(0) + , m_bIs_Channel(FALSE) + , m_dwFlags(0) + , m_wLast_ModuleID(1) + , m_hShared(NULL) + , m_cMemory(10240) + , m_pVargs(NULL) + , m_szVargs(0) +{ + if (i_pConf) + { + m_sConf = *i_pConf; + } + else + { + memset(&m_sConf, 0, sizeof(m_sConf)); + } + + memset(&m_sCS, 0, sizeof(m_sCS)); + + LOCK_CREATE(m_sCS); + + memset(&m_sHeader_Info, 0, sizeof(m_sHeader_Info)); + memset(&m_sHeader_Data, 0, sizeof(m_sHeader_Data)); + memset(&m_sHeader_Utc, 0, sizeof(m_sHeader_Utc)); + memset(m_pDesc_Array, 0, sizeof(m_pDesc_Array)); + + m_sStatus.bConnected = TRUE; + m_sStatus.dwResets = 0; + + if (NULL == m_pClient) + { + m_bInitialized = FALSE; + P7_Set_Last_Error(eP7_Error_NoClient); + } + else + { + const tXCHAR *l_pVerbosiry = m_pClient->Get_Argument(CLIENT_COMMAND_TRACE_VERBOSITY); + if (l_pVerbosiry) + { + eP7Trace_Level l_eVerbosity = (eP7Trace_Level)PStrToInt(l_pVerbosiry); + if ( (l_eVerbosity < EP7TRACE_LEVEL_COUNT) + && (l_eVerbosity >= EP7TRACE_LEVEL_TRACE) + ) + { + m_eVerbosity = l_eVerbosity; + } + } + + m_pClient->Add_Ref(); + } + + if (m_bInitialized) + { + m_bInitialized = Inc_Chunks(256); + + if (!m_bInitialized) + { + P7_Set_Last_Error(eP7_Error_MemoryAllocation); + } + } + + if (m_bInitialized) + { + INIT_EXT_HEADER(m_sHeader_Info.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_INFO, sizeof(m_sHeader_Info)); + //m_sHeader_Info.sCommon.dwSize = sizeof(sP7Trace_Info); + //m_sHeader_Info.sCommon.dwType = EP7USER_TYPE_TRACE; + //m_sHeader_Info.sCommon.dwSubType = EP7TRACE_TYPE_INFO; + + INIT_EXT_HEADER(m_sHeader_Data.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_DATA, 0); + //m_sHeader_Data.sCommon.dwType = EP7USER_TYPE_TRACE; + //m_sHeader_Data.sCommon.dwSubType = EP7TRACE_TYPE_DATA; + + if (i_pName) + { + PUStrCpy(m_sHeader_Info.pName, P7TRACE_NAME_LENGTH, i_pName); + } + else + { + PUStrCpy(m_sHeader_Info.pName, P7TRACE_NAME_LENGTH, TM("Unknown")); + } + + if (m_sConf.qwTimestamp_Frequency) + { + m_sHeader_Info.qwTimer_Frequency = m_sConf.qwTimestamp_Frequency; + m_sHeader_Info.qwTimer_Value = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + else + { + m_sHeader_Info.qwTimer_Frequency = GetPerformanceFrequency(); + m_sHeader_Info.qwTimer_Value = GetPerformanceCounter(); + } + + GetEpochTime(&m_sHeader_Info.dwTime_Hi, &m_sHeader_Info.dwTime_Lo); + + m_sHeader_Info.qwFlags = P7TRACE_INFO_FLAG_EXTENTION | P7TRACE_INFO_FLAG_TIME_ZONE; + + //Add main header to delivery chunks list + m_pChk_Curs->dwSize = sizeof(m_sHeader_Info); + m_pChk_Curs->pData = &m_sHeader_Info; + m_dwChk_Size += m_pChk_Curs->dwSize; + + m_pChk_Curs ++; + + //Add utc offset information + INIT_EXT_HEADER(m_sHeader_Utc.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_UTC_OFFS, sizeof(m_sHeader_Utc)); + m_sHeader_Utc.iUtcOffsetSec = GetUtcOffsetSeconds(); + + //Add utc header to delivery chunks list + m_pChk_Curs->dwSize = sizeof(m_sHeader_Utc); + m_pChk_Curs->pData = &m_sHeader_Utc; + m_dwChk_Size += m_pChk_Curs->dwSize; + + m_pChk_Curs ++; + } + + /////////////////////////////////////////////////////////////////////////// + // This code is dedicated to printing stack in case of crash, main idea is + // preallocate trace messages and all related memory for quick stack dump + // without allocation any new memory, but for the moment this functionality + // is frozen + // if (m_bInitialized) + // { + // tKeyType l_pKey[P7TRACE_KEY_LENGTH]; + // l_pKey[0] = (tKeyType)FORMAT_FUNC_UNKNOWN; + // l_pKey[1] = (tKeyType)FORMAT_CRASH_MESSAGE; + // + // m_wDesc_Tree_ID ++; + // m_cDescU_Tree.Push(new CP7Trace_Desc(m_wDesc_Tree_ID, + // 0, + // 0, + // FORMAT_FILE_UNKNOWN, + // FORMAT_FUNC_UNKNOWN, + // FORMAT_CRASH_MESSAGE + // ), + // l_pKey + // ); + // + // l_pKey[0] = (tKeyType)FORMAT_FUNC_UNKNOWN; + // l_pKey[1] = (tKeyType)FORMAT_STACK_MESSAGE; + // + // m_wDesc_Tree_ID ++; + // m_cDescU_Tree.Push(new CP7Trace_Desc(m_wDesc_Tree_ID, + // 0, + // 0, + // FORMAT_FILE_UNKNOWN, + // FORMAT_FUNC_UNKNOWN, + // FORMAT_STACK_MESSAGE + // ), + // l_pKey + // ); + // } + //////////////////////////////////////////////////////////////////////////// + // tUINT32 l_dwCount = 0; + // const CStackTrace::sStack *l_pStack = m_cStack_Trace.Get_Stack(&l_dwCount, 0); + // + // *io_pCrash = FALSE; + // + // if (l_dwCount) + // { + // Trace(0, + // EP7TRACE_LEVEL_CRITICAL, + // 0, + // 0, + // FORMAT_FILE_UNKNOWN, + // FORMAT_FUNC_UNKNOWN, + // FORMAT_CRASH_MESSAGE + // ); + // + // for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI ++) + // { + // Trace(0, + // EP7TRACE_LEVEL_INFO, + // 0, + // 0, + // FORMAT_FILE_UNKNOWN, + // FORMAT_FUNC_UNKNOWN, + // FORMAT_STACK_MESSAGE, + // l_dwI, + // l_pStack[l_dwI].pAddr, + // l_pStack[l_dwI].pName, + // l_pStack[l_dwI].dwLine + // ); + // } + // + // } + + + if (m_bInitialized) + { + m_bIs_Channel = (ECLIENT_STATUS_OK == m_pClient->Register_Channel(this)); + m_bInitialized = m_bIs_Channel; + if (!m_bInitialized) + { + P7_Set_Last_Error(eP7_Error_NoFreeChannels); + } + } + +#if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + if (m_bInitialized) + { + m_szVargs = 256; + m_pVargs = (tUINT8*)m_cMemory.Reuse(CMemoryManager::eVaValues, m_szVargs); + } +#else + if (m_bInitialized) + { + CP7Trace::sStack_Desc l_pDesc[6]; + l_pDesc[0].uValue.dw32 = 0xDEADBEEFu; + l_pDesc[0].eType = CP7Trace::sStack_Desc::eTypeU32; + l_pDesc[0].bLast = FALSE; + + l_pDesc[1].uValue.dw64 = 0x99ABCDEF12345678ull; + l_pDesc[1].eType = CP7Trace::sStack_Desc::eTypeU64; + l_pDesc[1].bLast = FALSE; + + l_pDesc[2].uValue.dw32 = 0xABBADEFEu; + l_pDesc[2].eType = CP7Trace::sStack_Desc::eTypeU32; + l_pDesc[2].bLast = FALSE; + + l_pDesc[3].uValue.dw32 = 0x98765432u; + l_pDesc[3].eType = CP7Trace::sStack_Desc::eTypeU32; + l_pDesc[3].bLast = FALSE; + + l_pDesc[4].uValue.db64 = (tDOUBLE)362764.9; + l_pDesc[4].eType = CP7Trace::sStack_Desc::eTypeD64; + l_pDesc[4].bLast = FALSE; + + l_pDesc[5].uValue.dw64 = 0x791A90204E0b4C6Dull; + l_pDesc[5].eType = CP7Trace::sStack_Desc::eTypeU64; + l_pDesc[5].bLast = TRUE; + + if (!Is_VarArgs(l_pDesc, + l_pDesc[0].uValue.dw32, + l_pDesc[1].uValue.dw64, + l_pDesc[2].uValue.dw32, + l_pDesc[3].uValue.dw32, + l_pDesc[4].uValue.db64, + l_pDesc[5].uValue.dw64 + ) + ) + { + printf("ERROR: P7.Trace detects that current architecture/compiler\n"); + printf(" doesn't support location of variadic arguments on stack\n"); + printf(" to make library works properly please activate macro\n"); + printf(" \"P7TRACE_NO_VA_ARG_OPTIMIZATION\" in file \"P7_Trace.h\"\n"); + printf(" Sorry for inconvenience and have a nice day!\n"); + } + } +#endif + + m_bActive = m_bInitialized; +} + + +//////////////////////////////////////////////////////////////////////////////// +// ~CP7Trace +CP7Trace::~CP7Trace() +{ + LOCK_ENTER(m_sCS); + LOCK_EXIT(m_sCS); + + if (m_hShared) + { + CShared::Close(m_hShared); + m_hShared = NULL; + } + + if (m_bIs_Channel) + { + Flush(); + + m_pClient->Unregister_Channel(m_dwChannel_ID); + } + + //memory used from pool, not necessary to return + memset(m_pDesc_Array, 0, sizeof(m_pDesc_Array)); + + m_cThreadsR.Clear(TRUE); + m_cThreadsS.Clear(TRUE); + m_cModules.Clear(TRUE); + + m_cDescU_Tree.Clear(); + m_cDescM_Tree.Clear(); + + if (m_pClient) + { + m_pClient->Release(); + m_pClient = NULL; + } + + if (m_pChk_Head) + { + free(m_pChk_Head); + m_pChk_Head = NULL; + } + + m_pChk_Curs = NULL; + m_dwChk_Count = 0; + + m_pVargs = NULL; + m_szVargs = 0; + + LOCK_DESTROY(m_sCS); +}// ~CP7Trace + + +//////////////////////////////////////////////////////////////////////////////// +// Is_Initialized +tBOOL CP7Trace::Is_Initialized() +{ + return m_bInitialized; +}// Is_Initialized + + +//////////////////////////////////////////////////////////////////////////////// +// On_Init +void CP7Trace::On_Init(sP7C_Channel_Info *i_pInfo) +{ + if (i_pInfo) + { + m_dwChannel_ID = i_pInfo->dwID; + } +}// On_Init + + +//////////////////////////////////////////////////////////////////////////////// +// On_Receive +void CP7Trace::On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian) +{ + UNUSED_ARG(i_dwChannel); + + LOCK_ENTER(m_sCS); + + if ( (i_pBuffer) + && (i_dwSize >= sizeof(sP7Ext_Header)) + ) + { + sP7Ext_Raw l_sHeader = *(sP7Ext_Raw*)i_pBuffer; + + if (EP7USER_TYPE_TRACE == GET_EXT_HEADER_TYPE(l_sHeader)) + { + if (EP7TRACE_TYPE_VERB == GET_EXT_HEADER_SUBTYPE(l_sHeader)) + { + sP7Trace_Module *l_pModule = NULL; + + if (i_bBigEndian) + { + ((sP7Trace_Verb*)i_pBuffer)->wModuleID = htons(((sP7Trace_Verb*)i_pBuffer)->wModuleID); + ((sP7Trace_Verb*)i_pBuffer)->eVerbosity = (eP7Trace_Level)htonl(((sP7Trace_Verb*)i_pBuffer)->eVerbosity); + } + + //if it is old protocol and field wModuleID isn't included into command + //or if module ID is 0 + if ( (i_dwSize < sizeof(sP7Trace_Verb)) + || (!((sP7Trace_Verb*)i_pBuffer)->wModuleID) + ) + { + m_eVerbosity = ((sP7Trace_Verb*)i_pBuffer)->eVerbosity; + } + else //set module verbosity + { + tUINT16 l_wModuleID = ((sP7Trace_Verb*)i_pBuffer)->wModuleID - 1; + pAList_Cell l_pEl = NULL; + sModules *l_pModules = NULL; + + l_pEl = NULL; + while ((l_pEl = m_cModules.Get_Next(l_pEl))) + { + l_pModules = m_cModules.Get_Data(l_pEl); + if (l_pModules->dwUsed > l_wModuleID) + { + l_pModules->pData[l_wModuleID].eVerbosity = ((sP7Trace_Verb*)i_pBuffer)->eVerbosity; + l_pModule = &l_pModules->pData[l_wModuleID]; + break; + } + else + { + l_wModuleID -= l_pModules->dwUsed; + } + }//while (l_pEl = m_cThreadsR.Get_Next(l_pEl)) + } + + if (m_sConf.pVerbosity_Callback) + { + m_sConf.pVerbosity_Callback(m_sConf.pContext, l_pModule, ((sP7Trace_Verb*)i_pBuffer)->eVerbosity); + } + } + else if (EP7TRACE_TYPE_DELETE == GET_EXT_HEADER_SUBTYPE(l_sHeader)) + { + Flush(); + m_bActive = FALSE; + } + } + } + + LOCK_EXIT(m_sCS); +}// On_Receive + + +//////////////////////////////////////////////////////////////////////////////// +// On_Status +void CP7Trace::On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus) +{ + UNUSED_ARG(i_dwChannel); + + LOCK_ENTER(m_sCS); + if (i_pStatus) + { + //if connection was established - sent threads info ... + if ( (i_pStatus->dwResets != m_sStatus.dwResets) + && (i_pStatus->bConnected) + ) + { + pAList_Cell l_pEl = NULL; + sThreadsR *l_pThreadsR = NULL; + sThreadsS *l_pThreadsS = NULL; + sModules *l_pModules = NULL; + + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + + //Add main header to delivery chunks list + m_pChk_Curs->dwSize = sizeof(m_sHeader_Info); + m_pChk_Curs->pData = &m_sHeader_Info; + m_dwChk_Size += m_pChk_Curs->dwSize; + + m_pChk_Curs ++; + + //Add utc offset header to delivery chunks list + m_pChk_Curs->dwSize = sizeof(m_sHeader_Utc); + m_pChk_Curs->pData = &m_sHeader_Utc; + m_dwChk_Size += m_pChk_Curs->dwSize; + + m_pChk_Curs ++; + + //add active threads desc. to delivery chunks list + l_pEl = NULL; + while ((l_pEl = m_cThreadsR.Get_Next(l_pEl))) + { + l_pThreadsR = m_cThreadsR.Get_Data(l_pEl); + if (l_pThreadsR->dwUsed) + { + m_pChk_Curs->pData = l_pThreadsR->pData; + m_pChk_Curs->dwSize = sizeof(sP7Trace_Thread_Start) * l_pThreadsR->dwUsed; + m_dwChk_Size += m_pChk_Curs->dwSize; + m_pChk_Curs ++; + + if (m_pChk_Curs >= m_pChk_Tail) + { + Inc_Chunks(64); + } + } + }//while (l_pEl = m_cThreadsR.Get_Next(l_pEl)) + + //add stopped threads desc. to delivery chunks list + l_pEl = NULL; + while ((l_pEl = m_cThreadsS.Get_Next(l_pEl))) + { + l_pThreadsS = m_cThreadsS.Get_Data(l_pEl); + if (l_pThreadsR->dwUsed) + { + m_pChk_Curs->pData = l_pThreadsS->pData; + m_pChk_Curs->dwSize = sizeof(sP7Trace_Thread_Stop) * l_pThreadsS->dwUsed; + m_dwChk_Size += m_pChk_Curs->dwSize; + m_pChk_Curs ++; + + if (m_pChk_Curs >= m_pChk_Tail) + { + Inc_Chunks(64); + } + } + }//while (l_pEl = m_cThreadsR.Get_Next(l_pEl)) + + //add modules descriptions to chunks list + l_pEl = NULL; + while ((l_pEl = m_cModules.Get_Next(l_pEl))) + { + l_pModules = m_cModules.Get_Data(l_pEl); + if (l_pModules->dwUsed) + { + m_pChk_Curs->pData = l_pModules->pData; + m_pChk_Curs->dwSize = sizeof(sP7Trace_Module) * l_pModules->dwUsed; + m_dwChk_Size += m_pChk_Curs->dwSize; + m_pChk_Curs ++; + + if (m_pChk_Curs >= m_pChk_Tail) + { + Inc_Chunks(64); + } + } + }//while (l_pEl = m_cThreadsR.Get_Next(l_pEl)) + + }//(i_pStatus->dwResets != m_sStatus.dwResets) ... + + m_sStatus = *i_pStatus; + + if (m_sConf.pConnect_Callback) + { + m_sConf.pConnect_Callback(m_sConf.pContext, m_sStatus.bConnected); + } + } + LOCK_EXIT(m_sCS); +}// On_Status + + +//////////////////////////////////////////////////////////////////////////////// +// On_Flush - external call +void CP7Trace::On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash) +{ + UNUSED_ARG(i_dwChannel); + + LOCK_ENTER(m_sCS); + + if ( (io_pCrash) + && (TRUE == *io_pCrash) + && (m_bActive) + ) + { + //nothing special for crash event + } + + Flush(); + + LOCK_EXIT(m_sCS); +}// On_Flush + + +//////////////////////////////////////////////////////////////////////////////// +// Register_Thread +tBOOL CP7Trace::Register_Thread(const tXCHAR *i_pName, tUINT32 i_dwThreadId) +{ + tBOOL l_bExtended = FALSE; + tBOOL l_bReturn = TRUE; + + if (NULL == i_pName) + { + return FALSE; + } + + LOCK_ENTER(m_sCS); + + sP7Trace_Thread_Start *l_pThread = NULL; + sThreadsR *l_pThreads = m_cThreadsR.Get_Data(m_cThreadsR.Get_Last()); + sP7C_Data_Chunk *l_pChunk = m_pChk_Head; + + if ( (NULL == l_pThreads) + || (l_pThreads->dwUsed >= l_pThreads->dwCount) + ) + { + if ((m_cThreadsR.Count() * P7TRACE_THREADS_POOL_SIZE) < P7TRACE_THREADS_MAX_SIZE) + { + l_pThreads = new sThreadsR(P7TRACE_THREADS_POOL_SIZE); + m_cThreadsR.Add_After(m_cThreadsR.Get_Last(), l_pThreads); + } + else + { + l_bReturn = FALSE; + goto l_lblExit; + } + } + + l_pThread = &l_pThreads->pData[l_pThreads->dwUsed]; + l_pThreads->dwUsed ++; + + INIT_EXT_HEADER(l_pThread->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_THREAD_START, sizeof(sP7Trace_Thread_Start)); + //l_pThread->sCommon.dwSize = sizeof(sP7Trace_Thread_Start); + //l_pThread->sCommon.dwType = EP7USER_TYPE_TRACE; + //l_pThread->sCommon.dwSubType = EP7TRACE_TYPE_THREAD_START; + + l_pThread->dwThreadID = (!i_dwThreadId) ? CProc::Get_Thread_Id() : i_dwThreadId; + + if (! m_sConf.pTimestamp_Callback ) + { + l_pThread->qwTimer = GetPerformanceCounter(); + } + else + { + l_pThread->qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + +#ifdef UTF8_ENCODING + PStrCpy(l_pThread->pName, P7TRACE_THREAD_NAME_LENGTH, i_pName); +#else + Convert_UTF16_To_UTF8((const tWCHAR*)i_pName, + l_pThread->pName, + P7TRACE_THREAD_NAME_LENGTH + ); +#endif + + //look for existing chunks which can be updated + while (l_pChunk < m_pChk_Curs) + { + //if new thread address is beginning of existing chunk pointer + if (((tUINT8*)l_pThread + sizeof(sP7Trace_Thread_Start)) == l_pChunk->pData) + { + l_pChunk->pData = l_pThread; + l_pChunk->dwSize += sizeof(sP7Trace_Thread_Start); + m_dwChk_Size += sizeof(sP7Trace_Thread_Start); + l_bExtended = TRUE; + break; + } + //if new thread address is continuation of existing chunk pointer + else if (((tUINT8*)l_pChunk->pData + l_pChunk->dwSize) == (tUINT8*)l_pThread) + { + l_pChunk->dwSize += sizeof(sP7Trace_Thread_Start); + m_dwChk_Size += sizeof(sP7Trace_Thread_Start); + l_bExtended = TRUE; + break; + } + + l_pChunk ++; + } + + //if chunk was not extended ... + if (FALSE == l_bExtended) + { + //Add thread header to delivery chunks list + m_pChk_Curs->dwSize = sizeof(sP7Trace_Thread_Start); + m_pChk_Curs->pData = l_pThread; + m_dwChk_Size += m_pChk_Curs->dwSize; + m_pChk_Curs ++; + + if (m_pChk_Curs >= m_pChk_Tail) + { + Inc_Chunks(64); + } + } + + if ( (m_sStatus.bConnected) + && (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(m_pChk_Curs - m_pChk_Head), + m_dwChk_Size + ) + ) + ) + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + } + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; +}//Register_Thread + + +//////////////////////////////////////////////////////////////////////////////// +// Unregister_Thread +tBOOL CP7Trace::Unregister_Thread(tUINT32 i_dwThreadId) +{ + tBOOL l_bReturn = FALSE; + sThreadsR *l_pStarted = NULL; + sThreadsS *l_pStopped = NULL; + sP7Trace_Thread_Stop *l_pStop = NULL; + pAList_Cell l_pEl = NULL; + + if (!i_dwThreadId) + { + i_dwThreadId = CProc::Get_Thread_Id(); + } + + LOCK_ENTER(m_sCS); + + while ((l_pEl = m_cThreadsR.Get_Next(l_pEl))) + { + l_pStarted = m_cThreadsR.Get_Data(l_pEl); + for (tUINT32 l_dwI = 0; l_dwI < l_pStarted->dwUsed; l_dwI++) + { + if (i_dwThreadId == l_pStarted->pData[l_dwI].dwThreadID) + { + l_bReturn = TRUE; + break; + } + } + } + + //such thread isn't registered ! + if (!l_bReturn) + { + goto l_lblExit; + } + + //save current Stop command in queue + l_pStopped = m_cThreadsS.Get_Data(m_cThreadsS.Get_Last()); + + if ( (NULL == l_pStopped) + || (l_pStopped->dwUsed >= l_pStopped->dwCount) + ) + { + if ((m_cThreadsS.Count() * P7TRACE_THREADS_POOL_SIZE) < P7TRACE_THREADS_MAX_SIZE) + { + l_pStopped = new sThreadsS(P7TRACE_THREADS_POOL_SIZE); + m_cThreadsS.Add_After(m_cThreadsS.Get_Last(), l_pStopped); + } + else + { + l_bReturn = FALSE; + goto l_lblExit; + } + } + + l_pStop = &l_pStopped->pData[l_pStopped->dwUsed]; + l_pStopped->dwUsed ++; + + INIT_EXT_HEADER(l_pStop->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_THREAD_STOP, sizeof(sP7Trace_Thread_Stop)); + //l_pStop->sCommon.dwSize = sizeof(sP7Trace_Thread_Stop); + //l_pStop->sCommon.dwType = EP7USER_TYPE_TRACE; + //l_pStop->sCommon.dwSubType = EP7TRACE_TYPE_THREAD_STOP; + + l_pStop->dwThreadID = i_dwThreadId; + if (! m_sConf.pTimestamp_Callback ) + { + l_pStop->qwTimer = GetPerformanceCounter(); + } + else + { + l_pStop->qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + + if (m_pChk_Curs >= m_pChk_Tail) + { + Inc_Chunks(64); + } + + m_pChk_Curs->pData = l_pStop; + m_pChk_Curs->dwSize = GET_EXT_HEADER_SIZE(l_pStop->sCommonRaw); + + m_dwChk_Size += m_pChk_Curs->dwSize; + m_pChk_Curs ++; + + if ( (m_sStatus.bConnected) + && (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(m_pChk_Curs - m_pChk_Head), + m_dwChk_Size + ) + ) + ) + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + + //delete all closed threads and related active threads + while ((l_pEl = m_cThreadsS.Get_Last())) + { + l_pStopped = m_cThreadsS.Get_Data(l_pEl); + + for (tUINT32 l_dwI = 0; l_dwI < l_pStopped->dwUsed; l_dwI++) + { + sP7Trace_Thread_Start *l_pCurrent = NULL; + sP7Trace_Thread_Start *l_pLast = NULL; + pAList_Cell l_pElR = NULL; + + //looking through active threads to find thread by ID + while ((l_pElR = m_cThreadsR.Get_Next(l_pElR))) + { + l_pStarted = m_cThreadsR.Get_Data(l_pElR); + + for (tUINT32 l_dwJ = 0; l_dwJ < l_pStarted->dwUsed; l_dwJ++) + { + if (l_pStopped->pData[l_dwI].dwThreadID == l_pStarted->pData[l_dwJ].dwThreadID) + { + l_pCurrent = &l_pStarted->pData[l_dwJ]; + break; + } + } + + if (l_pCurrent) + { + sThreadsR *l_pLastR = m_cThreadsR.Get_Data(m_cThreadsR.Get_Last()); + + if ( (l_pLastR) + && (l_pLastR->dwUsed) + ) + { + l_pLast = &l_pLastR->pData[l_pLastR->dwUsed - 1]; + + if (l_pLast != l_pCurrent) + { + memcpy(l_pCurrent, l_pLast, sizeof(sP7Trace_Thread_Start)); + } + + l_pLastR->dwUsed --; + + if ( (0 == l_pLastR->dwUsed) + && (1 < m_cThreadsR.Count()) + ) + { + m_cThreadsR.Del(m_cThreadsR.Get_Last(), TRUE); + } + } + + break; + } + }//while (l_pElR = m_cThreadsR.Get_Next(l_pElR)) + }//for (tUINT32 l_dwI = 0; l_dwI < l_pStopped->dwUsed; l_dwI++) + + m_cThreadsS.Del(l_pEl, TRUE); + }//while (l_pEl = m_cThreadsS.Get_Last()) + } //m_pClient->Sent(...) + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Unregister_Thread + + +//////////////////////////////////////////////////////////////////////////////// +// Register_Module +tBOOL CP7Trace::Register_Module(const tXCHAR *i_pName, IP7_Trace::hModule *o_hModule) +{ + if ( (NULL == i_pName) + || (NULL == o_hModule) + ) + { + return FALSE; + } + + LOCK_ENTER(m_sCS); + tBOOL l_bReturn = TRUE; + sP7Trace_Module *l_pModule = NULL; + sModules *l_pModules = m_cModules.Get_Data(m_cModules.Get_Last()); + sP7C_Data_Chunk *l_pChunk = m_pChk_Head; + tBOOL l_bExtended = FALSE; + sModuleMap *l_pMap = NULL; + + //looking through existing modules -if found - return it + l_pMap = m_cModules_Map.Find(i_pName); + if (l_pMap) + { + *o_hModule = l_pMap->pModule; + goto l_lblExit; + } + + //module isn't exists - create new one + if ( (NULL == l_pModules) + || (l_pModules->dwUsed >= l_pModules->dwCount) + ) + { + if ((m_cModules.Count() * P7TRACE_MODULES_POOL_SIZE) < P7TRACE_MODULES_MAX_SIZE) + { + l_pModules = new sModules(P7TRACE_MODULES_POOL_SIZE); + m_cModules.Add_After(m_cModules.Get_Last(), l_pModules); + } + else + { + l_bReturn = FALSE; + goto l_lblExit; + } + } + + l_pModule = &l_pModules->pData[l_pModules->dwUsed]; + l_pModules->dwUsed ++; + + INIT_EXT_HEADER(l_pModule->sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_MODULE, sizeof(sP7Trace_Module)); + //l_pModule->sCommon.dwSize = sizeof(sP7Trace_Module); + //l_pModule->sCommon.dwType = EP7USER_TYPE_TRACE; + //l_pModule->sCommon.dwSubType = EP7TRACE_TYPE_MODULE; + + l_pModule->eVerbosity = m_eVerbosity; + l_pModule->wModuleID = m_wLast_ModuleID++; + +#ifdef UTF8_ENCODING + PStrCpy(l_pModule->pName, P7TRACE_THREAD_NAME_LENGTH, i_pName); +#else + Convert_UTF16_To_UTF8((const tWCHAR*)i_pName, + l_pModule->pName, + P7TRACE_MODULE_NAME_LENGTH + ); +#endif + + //add module to tree + l_pMap = new sModuleMap(i_pName, l_pModule); + if (!m_cModules_Map.Push(l_pMap, i_pName)) + { + delete l_pMap; + l_pMap = NULL; + } + + //look for existing chunks which can be updated + while (l_pChunk < m_pChk_Curs) + { + //if new thread address is beginning of existing chunk pointer + if (((tUINT8*)l_pModule + sizeof(sP7Trace_Module)) == l_pChunk->pData) + { + l_pChunk->pData = l_pModule; + l_pChunk->dwSize += sizeof(sP7Trace_Module); + m_dwChk_Size += sizeof(sP7Trace_Module); + l_bExtended = TRUE; + break; + } + //if new thread address is continuation of existing chunk pointer + else if (((tUINT8*)l_pChunk->pData + l_pChunk->dwSize) == (tUINT8*)l_pModule) + { + l_pChunk->dwSize += sizeof(sP7Trace_Module); + m_dwChk_Size += sizeof(sP7Trace_Module); + l_bExtended = TRUE; + break; + } + + l_pChunk ++; + } + + //if chunk was not extended ... + if (FALSE == l_bExtended) + { + //Add thread header to delivery chunks list + m_pChk_Curs->dwSize = sizeof(sP7Trace_Module); + m_pChk_Curs->pData = l_pModule; + m_dwChk_Size += m_pChk_Curs->dwSize; + m_pChk_Curs ++; + + if (m_pChk_Curs >= m_pChk_Tail) + { + Inc_Chunks(64); + } + } + + //deliver + if ( (m_sStatus.bConnected) + && (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(m_pChk_Curs - m_pChk_Head), + m_dwChk_Size + ) + ) + ) + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + } + + *o_hModule = l_pModule; + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Register_Module + + +//////////////////////////////////////////////////////////////////////////////// +// Set_Verbosity +void CP7Trace::Set_Verbosity(IP7_Trace::hModule i_hModule, eP7Trace_Level i_eVerbosity) +{ + LOCK_ENTER(m_sCS); + sP7C_Data_Chunk *l_pChunk = NULL; + tUINT32 l_dwSize = m_dwChk_Size; + sP7Trace_Verb l_sCmd; + + if (i_hModule) + { + ((sP7Trace_Module*)i_hModule)->eVerbosity = i_eVerbosity; + } + else + { + m_eVerbosity = i_eVerbosity; + } + + if (m_pChk_Curs >= m_pChk_Tail) + { + if (!Inc_Chunks(64)) + { + goto l_lblExit; + } + } + + l_pChunk = m_pChk_Curs; + + + INIT_EXT_HEADER(l_sCmd.sCommonRaw, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_VERB, sizeof(sP7Trace_Verb)); + //l_sCmd.sCommon.dwSize = sizeof(sP7Trace_Verb); + //l_sCmd.sCommon.dwType = EP7USER_TYPE_TRACE; + //l_sCmd.sCommon.dwSubType = EP7TRACE_TYPE_VERB; + + l_sCmd.eVerbosity = i_eVerbosity; + l_sCmd.wModuleID = (i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0; + + l_pChunk->pData = &l_sCmd; + l_pChunk->dwSize = GET_EXT_HEADER_SIZE(l_sCmd.sCommonRaw); + l_dwSize += GET_EXT_HEADER_SIZE(l_sCmd.sCommonRaw); + + l_pChunk++; + + //deliver + if ( (m_sStatus.bConnected) + && (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(l_pChunk - m_pChk_Head), + l_dwSize + ) + ) + ) + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + } + +l_lblExit: + LOCK_EXIT(m_sCS); +}// Set_Verbosity + + +//////////////////////////////////////////////////////////////////////////////// +// Get_Verbosity +eP7Trace_Level CP7Trace::Get_Verbosity(IP7_Trace::hModule i_hModule) +{ + eP7Trace_Level l_eReturn = EP7TRACE_LEVEL_COUNT; + LOCK_ENTER(m_sCS); + + if (i_hModule) + { + l_eReturn = ((sP7Trace_Module*)i_hModule)->eVerbosity; + } + else + { + l_eReturn = m_eVerbosity; + } + + LOCK_EXIT(m_sCS); + + return l_eReturn; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Trace +tBOOL CP7Trace::Trace(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR *i_pFormat, + ... + ) +{ +#if !defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + return Trace_Raw(i_wTrace_ID, + i_eLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + (tKeyType*)&i_pFunction, + &i_pFormat, + NULL + ); +#else + va_list l_pVl; + va_start(l_pVl, i_pFormat); + tKeyType l_pKey[2] = {(tKeyType)i_pFunction, (tKeyType)i_pFormat}; + tBOOL l_bRet = Trace_Raw(i_wTrace_ID, + i_eLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + l_pKey, + &i_pFormat, + &l_pVl + ); + va_end(l_pVl); + return l_bRet; +#endif +}// Trace + +//////////////////////////////////////////////////////////////////////////////// +// Share +tBOOL CP7Trace::Share(const tXCHAR *i_pName) +{ + tBOOL l_bReturn = FALSE; + + LOCK_ENTER(m_sCS); + if (NULL == m_hShared) + { + tUINT32 l_dwLen1 = PStrLen(TRACE_SHARED_PREFIX); + tUINT32 l_dwLen2 = PStrLen(i_pName); + tXCHAR *l_pName = (tXCHAR *)malloc(sizeof(tXCHAR) * (l_dwLen1 + l_dwLen2 + 16)); + CShared::hSem l_hSem = SHARED_SEM_NULL; + + if (l_pName) + { + sObjShared l_stShared = {}; + tUINT32 l_uTimeHi = 0; + tUINT32 l_uTimeLo = 0; + tBOOL l_bCreate = TRUE; + + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + + PStrCpy(l_pName, l_dwLen1 + l_dwLen2 + 16, TRACE_SHARED_PREFIX); + PStrCpy(l_pName + l_dwLen1, l_dwLen2 + 16, i_pName); + + //JOURNAL_WARNING(m_pLog, TM("Shared memory {%s} registration error"), l_pName); + if (CShared::E_OK == CShared::Lock(l_pName, l_hSem, 250)) + { + l_bCreate = FALSE; //it is already existing + + if (CShared::Read(l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared))) + { + if ( (l_stShared.uProcTimeHi != l_uTimeHi) + || (l_stShared.uProcTimeLo != l_uTimeLo) + ) + { + //JOURNAL_ERROR(m_pLog, TM("Shared memory timestamp error, prev. session crashed or forget to release P7 objects?")); + CShared::UnLink(l_pName); + l_bCreate = TRUE; + } + } + + CShared::UnLock(l_hSem); + } + + if (l_bCreate) + { + CProc::Get_Process_Time(&l_uTimeHi, &l_uTimeLo); + l_stShared.pPointer = static_cast(this); + l_stShared.uProcTimeHi = l_uTimeHi; + l_stShared.uProcTimeLo = l_uTimeLo; + + l_bReturn = CShared::Create(&m_hShared, l_pName, (tUINT8*)&l_stShared, sizeof(l_stShared)); + } + + free(l_pName); + l_pName = NULL; + } + } + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Share + + +//////////////////////////////////////////////////////////////////////////////// +// On_Flush - internal call +void CP7Trace::Flush() +{ + if (FALSE == m_bActive) + { + return; + } + + m_bActive = FALSE; + + sP7C_Data_Chunk *l_pChunk = m_pChk_Curs; + tUINT32 l_dwSize = m_dwChk_Size; + sP7Ext_Raw l_sHeader; + + INIT_EXT_HEADER(l_sHeader, EP7USER_TYPE_TRACE, EP7TRACE_TYPE_CLOSE, sizeof(sP7Ext_Raw)); + + l_pChunk->pData = &l_sHeader; + l_pChunk->dwSize = sizeof(sP7Ext_Raw); + l_dwSize += sizeof(sP7Ext_Raw); + + l_pChunk++; + + if (l_pChunk >= m_pChk_Tail) + { + Inc_Chunks(64); + } + + if (ECLIENT_STATUS_OK == m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(l_pChunk - m_pChk_Head), + l_dwSize + ) + ) + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + } +}// On_Flush + + +//////////////////////////////////////////////////////////////////////////////// +// Trace_Embedded +tBOOL CP7Trace::Trace_Embedded(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat + ) +{ +#if !defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + tKeyType l_pKey[P7TRACE_KEY_LENGTH] = {(tKeyType)i_pFunction, (tKeyType)*i_ppFormat}; + + return Trace_Raw(i_wTrace_ID, + i_eLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + l_pKey, + i_ppFormat, + NULL + ); +#else + UNUSED_ARG(i_wTrace_ID); + UNUSED_ARG(i_eLevel); + UNUSED_ARG(i_hModule); + UNUSED_ARG(i_wLine); + UNUSED_ARG(i_pFile); + UNUSED_ARG(i_pFunction); + UNUSED_ARG(i_ppFormat); + + static tBOOL g_bVaArgError = FALSE; + if (!g_bVaArgError) + { + g_bVaArgError = TRUE; + printf("P7 TRACE ERROR: Trace_Embedded function is obsolete!\n"); + } + return FALSE; +#endif +}// Trace_Embedded + + +//////////////////////////////////////////////////////////////////////////////// +// Trace_Embedded +tBOOL CP7Trace::Trace_Embedded(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ) +{ + tKeyType l_pKey[P7TRACE_KEY_LENGTH] = {(tKeyType)i_pFunction, (tKeyType)*i_ppFormat}; + + return Trace_Raw(i_wTrace_ID, + i_eLevel, + i_hModule, + i_wLine, + i_pFile, + i_pFunction, + l_pKey, + i_ppFormat, + i_pVa_List + ); +} + + +//////////////////////////////////////////////////////////////////////////////// +//Trace_Managed +tBOOL CP7Trace::Trace_Managed(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + const tXCHAR *i_pMessage + ) +{ + tBOOL l_bReturn = TRUE; + tUINT32 l_dwSize = 0; + CP7Trace_Desc *l_pDesc = NULL; + tBOOL l_bDesc = FALSE; + size_t l_szTrace = 0; + sP7C_Data_Chunk *l_pChunk; //we do not initialize it here, we do it later + + LOCK_ENTER(m_sCS); + + m_dwSequence ++; + + if ( (i_eLevel < m_eVerbosity) + || (FALSE == m_bActive) + || (FALSE == m_sStatus.bConnected) + || ( (i_hModule) + && (i_eLevel < ((sP7Trace_Module*)i_hModule)->eVerbosity) + ) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //if user specify direct Trace ID + if ( (1 <= i_wTrace_ID) + && (P7_TRACE_DESC_HARDCODED_COUNT > i_wTrace_ID) + ) + { + l_pDesc = m_pDesc_Array[i_wTrace_ID]; + if (NULL == l_pDesc) + { + l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc))) + CP7Trace_Desc(m_cMemory, + i_wTrace_ID, + i_wLine, + (i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0, + i_pFile, + i_pFunction, + (tKeyType*)NULL + ); + m_pDesc_Array[i_wTrace_ID] = l_pDesc; + } + } + else //if we should use map to find it + { + tKeyType l_pKeys[P7TRACE_KEY_LENGTH] = {0ul, 2166136261ul}; + const tXCHAR *l_pFile = i_pFile; + + //Here is RedBlackTree keys are calculated, key is consisting of 2 parts + //l_pKeys[0] = [16 bits: i_pFile string length][16 bits: line number] + //l_pKeys[1] = FNV-1a 32bits hash of i_pFile + //Hash description: http://isthe.com/chongo/tech/comp/fnv/#FNV-param + //Hash parameters investigation (collisions, randomnessification) + //http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed + //Collisions: + // - Is collisions are possible ? Yes, FNV-1a produce 4 coll. on list of + // 216,553 English words. But count of uniq. trace ID is limited to + // 64k, and in addition to hash I'm using second key containing string + // length and source code line number. + // - If collision happens and even calculated key is not unique - is it + // dangerous ? No, even in this hypothetical situation the maximal + // risk is displaying wrong [i_wLine, i_pFile, i_pFunction] values on + // Baical side + // - May we prevent not unique key issue ? Yes, but it will require in + // addition checking all 3 parameters [i_wLine, i_pFile, i_pFunction] + // after key searching in tree, this is heavy string operation for + // every trace message + // Conclusion: + // - real risk of hash collision is low on 64k unique traces + // - risk of calculating not unique key is much lower than collision due + // to different parameters combination in addition to hash + // - data damage in case of not unique key isn't significant, main + // trace message and all its parameters will be delivered properly, + // except [i_wLine, i_pFile, i_pFunction]. + // So additional protection wasn't implemented + while (*l_pFile) + { + l_pKeys[0] ++; //string length + l_pKeys[1] = (tKeyType)(l_pKeys[1] ^ (tXCHAR)*l_pFile) * 16777619ul; + l_pFile++; + } + + l_pKeys[0] = (l_pKeys[0] << 16) + (tKeyType)i_wLine; + + l_pDesc = m_cDescM_Tree.Find(l_pKeys); + if ( (NULL == l_pDesc) + && (0xFFFF > m_wDesc_Tree_ID) + ) + { + m_wDesc_Tree_ID ++; + l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc))) + CP7Trace_Desc(m_cMemory, + m_wDesc_Tree_ID, + i_wLine, + (i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0, + i_pFile, + i_pFunction, + l_pKeys + ); + //in stack we have pointer of the function and then format, 2 values + m_cDescM_Tree.Push(l_pDesc, l_pKeys); + } + } + + if ( (NULL == l_pDesc) + || (FALSE == l_pDesc->Is_Initialized()) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + //increase chunks count if it is necessary + if ((m_pChk_Curs + 8) >= m_pChk_Tail) + { + if (FALSE == Inc_Chunks(16)) + { + l_bReturn = FALSE; + goto l_lblExit; + } + } + + l_pChunk = m_pChk_Curs; + l_dwSize = m_dwChk_Size; + + //trace description have to send again + if (m_sStatus.dwResets != l_pDesc->Get_Resets()) + { + l_pDesc->Set_Resets(m_sStatus.dwResets); + + l_bDesc = TRUE; + l_pChunk->pData = l_pDesc->Get_Buffer(&l_pChunk->dwSize); + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + } + + m_sHeader_Data.bLevel = (tUINT8)i_eLevel; + m_sHeader_Data.bProcessor = (tUINT8)CProc::Get_Processor(); + m_sHeader_Data.dwThreadID = CProc::Get_Thread_Id(); + m_sHeader_Data.wID = l_pDesc->Get_ID(); + m_sHeader_Data.dwSequence = m_dwSequence; + + if (! m_sConf.pTimestamp_Callback ) + { + m_sHeader_Data.qwTimer = GetPerformanceCounter(); + } + else + { + m_sHeader_Data.qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + + l_pChunk->dwSize = sizeof(m_sHeader_Data); + l_pChunk->pData = &m_sHeader_Data; + + //we should also add all variable parameters length ... later + l_szTrace = sizeof(m_sHeader_Data); + //SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, ); + //m_sHeader_Data.sCommon.dwSize = sizeof(m_sHeader_Data); + + l_pChunk ++; + + //adding string message to chunk + if (!i_pMessage) + { + i_pMessage = TM("NULL"); + } + + l_pChunk->dwSize = (tUINT32)((PStrLen(i_pMessage) + 1) * sizeof(tXCHAR)); + l_pChunk->pData = (void*)i_pMessage; + l_szTrace += l_pChunk->dwSize; + + l_pChunk++; + + //Put extensions...///////////////////////////////////////////////////////////// + if (i_hModule) + { + #if defined(__linux__) //fix alignment and GCC warnings + memcpy(m_pExtensions, &(((sP7Trace_Module*)i_hModule)->wModuleID), sizeof(tUINT16)); + #else + *(tUINT16*)m_pExtensions = ((sP7Trace_Module*)i_hModule)->wModuleID; + #endif + + m_pExtensions[2] = (tUINT8)EP7TRACE_EXT_MODULE_ID; + m_pExtensions[3] = 1; + l_pChunk->pData = m_pExtensions; + l_pChunk->dwSize = 4u; + } + else + { + m_pExtensions[0] = 0; + l_pChunk->pData = m_pExtensions; + l_pChunk->dwSize = 1u; + } + + l_szTrace += l_pChunk->dwSize; + SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, l_szTrace); + l_pChunk ++; + + + l_dwSize += (tUINT32)l_szTrace; + + if (ECLIENT_STATUS_OK != m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(l_pChunk - m_pChk_Head), + l_dwSize + ) + ) + { + //if delivery was failed and we try to deliver also trace description + //we set marker that is should be redelivered next time + if (l_bDesc) + { + l_pDesc->Set_Resets(RESET_UNDEFINED); + } + + l_bReturn = FALSE; + } + else + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + } + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; + + + return l_bReturn; +}// Trace_Managed + + +//////////////////////////////////////////////////////////////////////////////// +// Trace_Raw +__forceinline tBOOL CP7Trace::Trace_Raw(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + tKeyType *i_pKey, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ) +{ + tBOOL l_bReturn = TRUE; + tUINT32 l_dwSize = 0; + CP7Trace_Desc *l_pDesc = NULL; + tINT32 *l_pBlocks = NULL; + tUINT32 l_dwBCount = 0; + tUINT8 *l_pVArgs = (tUINT8*)(i_ppFormat) + sizeof(tXCHAR*); + tBOOL l_bDesc = FALSE; + size_t l_szTrace = 0; + sP7C_Data_Chunk *l_pChunk; //we do not initialize it here, we do it later + + LOCK_ENTER(m_sCS); + + m_dwSequence ++; + + if ( (FALSE == m_bActive) + || (FALSE == m_sStatus.bConnected) + || ( ((i_hModule) && (i_eLevel < ((sP7Trace_Module*)i_hModule)->eVerbosity)) + || ((!i_hModule) && (i_eLevel < m_eVerbosity)) + ) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + //////////////////////////////////////////////////////////////////////////// + //if user specify direct Trace ID + if ( (1 <= i_wTrace_ID) + && (P7_TRACE_DESC_HARDCODED_COUNT > i_wTrace_ID) + ) + { + l_pDesc = m_pDesc_Array[i_wTrace_ID]; + if (NULL == l_pDesc) + { + l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc))) + CP7Trace_Desc(m_cMemory, + i_wTrace_ID, + i_wLine, + (i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0, + i_pFile, + i_pFunction, + i_ppFormat, + i_pKey, + m_dwFlags + ); + m_pDesc_Array[i_wTrace_ID] = l_pDesc; + + #if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + if ((l_pDesc->Get_Arguments_Count() * 16) > m_szVargs) + { + m_szVargs = l_pDesc->Get_Arguments_Count() * 16; + m_pVargs = (tUINT8*)m_cMemory.Reuse(CMemoryManager::eVaValues, m_szVargs); + } + #endif + } + } + else //if we should use map to find it + { + //This moment should be clarified: + //Here we made search through RB tree by key. Key consist of 2 values + // - address of function + // - address of format string + //They located in stack [i_pFunction][*i_ppFormat] + //Function eTrace work with stack of upper function like Trace(...) + //and we should operate by stack of that function. This is why here + //we get i_ppFormat, convert it to pointer (4 or 8 bytes depending on OS) + //and subtract one element to get pointer to the function name. + l_pDesc = m_cDescU_Tree.Find(i_pKey); + if ( (NULL == l_pDesc) + && (0xFFFF > m_wDesc_Tree_ID) + ) + { + m_wDesc_Tree_ID ++; + l_pDesc = new (m_cMemory.Alloc(sizeof(CP7Trace_Desc))) + CP7Trace_Desc(m_cMemory, + m_wDesc_Tree_ID, + i_wLine, + (i_hModule) ? ((sP7Trace_Module*)i_hModule)->wModuleID : 0, + i_pFile, + i_pFunction, + i_ppFormat, + i_pKey, + m_dwFlags + ); + //in stack we have pointer of the function and then format, 2 values + m_cDescU_Tree.Push(l_pDesc, i_pKey); + + #if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + if ((l_pDesc->Get_Arguments_Count() * 16) > m_szVargs) + { + m_szVargs = l_pDesc->Get_Arguments_Count() * 16; + m_pVargs = (tUINT8*)m_cMemory.Reuse(CMemoryManager::eVaValues, m_szVargs); + } + #endif + } + } + + if ( (NULL == l_pDesc) + || (FALSE == l_pDesc->Is_Initialized()) + //|| (l_pFormat != l_pDesc->Get_Key()) + ) + { + l_bReturn = FALSE; + goto l_lblExit; + } + + l_pBlocks = l_pDesc->Get_Blocks(&l_dwBCount); + //increase chunks count if it is necessary + if ( (l_dwBCount) + && ((m_pChk_Curs + l_dwBCount + TRACE_EXTRA_CHUNKS) >= m_pChk_Tail) + ) + { + if (FALSE == Inc_Chunks(l_dwBCount + TRACE_EXTRA_CHUNKS)) + { + l_bReturn = FALSE; + goto l_lblExit; + } + } + + l_pChunk = m_pChk_Curs; + l_dwSize = m_dwChk_Size; + + //trace description have to send again + if (m_sStatus.dwResets != l_pDesc->Get_Resets()) + { + l_pDesc->Set_Resets(m_sStatus.dwResets); + + l_bDesc = TRUE; + l_pChunk->pData = l_pDesc->Get_Buffer(&l_pChunk->dwSize); + l_dwSize += l_pChunk->dwSize; + l_pChunk ++; + } + + //we should also add all variable parameters length ... later + l_szTrace = sizeof(m_sHeader_Data); + //SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, ); + //m_sHeader_Data.sCommon.dwSize = sizeof(m_sHeader_Data); + + m_sHeader_Data.bLevel = (tUINT8)i_eLevel; + m_sHeader_Data.bProcessor = (tUINT8)CProc::Get_Processor(); + m_sHeader_Data.dwThreadID = CProc::Get_Thread_Id(); + m_sHeader_Data.wID = l_pDesc->Get_ID(); + m_sHeader_Data.dwSequence = m_dwSequence; + + if (! m_sConf.pTimestamp_Callback ) + { + m_sHeader_Data.qwTimer = GetPerformanceCounter(); + } + else + { + m_sHeader_Data.qwTimer = m_sConf.pTimestamp_Callback(m_sConf.pContext); + } + + l_pChunk->dwSize = sizeof(m_sHeader_Data); + l_pChunk->pData = &m_sHeader_Data; + + l_pChunk ++; + + //case for platforms where variadic arguments located in stack in specific order + //or using general purposes registers + #if defined(P7TRACE_NO_VA_ARG_OPTIMIZATION) + { + tUINT32 l_dwArgC; + const sP7Trace_Arg *l_pArgV = l_pDesc->Get_Arguments(l_dwArgC); + l_pVArgs = m_pVargs; + while (l_dwArgC--) + { + #if defined (GTX32) + if (4 == l_pArgV->bSize) //most probable case + { + *(tUINT32*)l_pVArgs = va_arg(*i_pVa_List, tUINT32); + } + else + #endif + if (8 == l_pArgV->bSize) + { + //GCC sometimes optimizes storing of double values and access to it requires + //specific case, "bardak i razruha v golovah" + if (P7TRACE_ARG_TYPE_DOUBLE != l_pArgV->bType) + { + //in some platforms access to 64 not aligned variable is illegal, if it + //the case, please active the macro P7TRACE_64BITS_ALIGNED_ACCESS in P7_Trace.h + #if defined(P7TRACE_64BITS_ALIGNED_ACCESS) + tUINT64 l_qwVal = va_arg(*i_pVa_List, tUINT64); + memcpy(l_pVArgs, &l_qwVal, sizeof(tUINT64)); + #else + *(tUINT64*)l_pVArgs = va_arg(*i_pVa_List, tUINT64); + #endif + } + else + { + //in some platforms access to 64 not aligned variable is illegal, if it + //the case, please active the macro P7TRACE_64BITS_ALIGNED_ACCESS in P7_Trace.h + #if defined(P7TRACE_64BITS_ALIGNED_ACCESS) + double l_qwVal = va_arg(*i_pVa_List, double); + memcpy(l_pVArgs, &l_qwVal, sizeof(double)); + #else + *(double*)l_pVArgs = va_arg(*i_pVa_List, double); + #endif + } + } + else if (0 == l_pArgV->bSize) + { + *(void**)l_pVArgs = va_arg(*i_pVa_List, void*); + l_pVArgs += SIZE_OF_ARG(void*); //String has 0 size (0 == l_pArgV->bSize) + } + else //if (SIZE_OF_ARG(uintmax_t) == l_pArgV->bSize) + { + //in some platforms access to 64 not aligned variable is illegal, if it + //the case, please active the macro P7TRACE_64BITS_ALIGNED_ACCESS in P7_Trace.h + #if defined(P7TRACE_64BITS_ALIGNED_ACCESS) + uintmax_t l_qwVal = va_arg(*i_pVa_List, uintmax_t); + memcpy(l_pVArgs, &l_qwVal, sizeof(uintmax_t)); + #else + *(uintmax_t*)l_pVArgs = va_arg(*i_pVa_List, uintmax_t); + #endif + } + + l_pVArgs += l_pArgV->bSize; + l_pArgV++; + } + l_pVArgs = m_pVargs; + } + #endif + + while (l_dwBCount --) + { + if (0 <= (*l_pBlocks)) + { + l_pChunk->dwSize = (*l_pBlocks); + l_pChunk->pData = l_pVArgs; + l_pVArgs += (*l_pBlocks); + } + else if (P7TRACE_ITEM_BLOCK_ASTRING == (*l_pBlocks)) + { + l_pChunk->pData = *(char**)l_pVArgs; + + if (l_pChunk->pData) + { + l_pChunk->dwSize = (tUINT32)strlen(*(char**)l_pVArgs) + 1; + } + else + { + l_pChunk->pData = const_cast("(NULL)"); + l_pChunk->dwSize = 7u; + } + + l_pVArgs += sizeof(char*); + } +#ifndef UTF8_ENCODING + else if (P7TRACE_ITEM_BLOCK_USTRING16 == (*l_pBlocks)) + { + l_pChunk->pData = *(wchar_t**)l_pVArgs; + + if (l_pChunk->pData) + { + l_pChunk->dwSize = (tUINT32)((wcslen(*(wchar_t**)l_pVArgs) + 1) * sizeof(wchar_t)); + } + else + { + l_pChunk->pData = const_cast(L"(NULL)"); + l_pChunk->dwSize = sizeof(wchar_t) * 7u; + } + + l_pVArgs += sizeof(wchar_t*); + } +#else + else if (P7TRACE_ITEM_BLOCK_USTRING32 == (*l_pBlocks)) + { + l_pChunk->pData = *(wchar_t**)l_pVArgs; + + if (l_pChunk->pData) + { + l_pChunk->dwSize = (tUINT32)((wcslen(*(wchar_t**)l_pVArgs) + 1) * sizeof(wchar_t)); + } + else + { + l_pChunk->pData = const_cast(L"(NULL)"); + l_pChunk->dwSize = sizeof(wchar_t) * 7u; + } + + l_pVArgs += sizeof(wchar_t*); + } +#endif + else if (P7TRACE_ITEM_BLOCK_ASTRING_FIX == (*l_pBlocks)) + { + l_pChunk->pData = const_cast("([x]s is unsupported by P7)"); + l_pChunk->dwSize = sizeof(char) * 28u; + l_pVArgs += sizeof(char*); + } + else if (P7TRACE_ITEM_BLOCK_WSTRING_FIX == (*l_pBlocks)) + { + l_pChunk->pData = const_cast(L"([x]s is unsupported by P7)"); + l_pChunk->dwSize = sizeof(wchar_t) * 28u; + l_pVArgs += sizeof(wchar_t*); + } + + l_szTrace += (size_t)l_pChunk->dwSize; + + l_pChunk ++; + l_pBlocks++; + } + + //Put extensions...///////////////////////////////////////////////////////////// + if (i_hModule) + { + #if defined(__linux__) //fix alignment and GCC warnings + memcpy(m_pExtensions, &(((sP7Trace_Module*)i_hModule)->wModuleID), sizeof(tUINT16)); + #else + *(tUINT16*)m_pExtensions = ((sP7Trace_Module*)i_hModule)->wModuleID; + #endif + + m_pExtensions[2] = (tUINT8)EP7TRACE_EXT_MODULE_ID; + m_pExtensions[3] = 1; + l_pChunk->pData = m_pExtensions; + l_pChunk->dwSize = 4u; + } + else + { + m_pExtensions[0] = 0; + l_pChunk->pData = m_pExtensions; + l_pChunk->dwSize = 1u; + } + + l_szTrace += l_pChunk->dwSize; + SET_EXT_HEADER_SIZE(m_sHeader_Data.sCommonRaw, l_szTrace); + l_pChunk ++; + + l_dwSize += (tUINT32)l_szTrace;//m_sHeader_Data.sCommon.dwSize; + + if (ECLIENT_STATUS_OK != m_pClient->Sent(m_dwChannel_ID, + m_pChk_Head, + (tUINT32)(l_pChunk - m_pChk_Head), + l_dwSize + ) + ) + { + //if delivery was failed and we try to deliver also trace description + //we set marker that is should be redelivered next time + if (l_bDesc) + { + l_pDesc->Set_Resets(RESET_UNDEFINED); + } + + l_bReturn = FALSE; + } + else + { + m_pChk_Curs = m_pChk_Head; + m_dwChk_Size = 0; + } + +l_lblExit: + LOCK_EXIT(m_sCS); + + return l_bReturn; +}// Trace_Raw + + +//////////////////////////////////////////////////////////////////////////////// +// Inc_Chunks +__forceinline tBOOL CP7Trace::Inc_Chunks(tUINT32 i_dwInc) +{ + size_t l_szUsed = m_pChk_Curs - m_pChk_Head; + sP7C_Data_Chunk *l_pChunks = (sP7C_Data_Chunk*)realloc(m_pChk_Head, + (m_dwChk_Count + i_dwInc) * sizeof(sP7C_Data_Chunk) + ); + + if (!l_pChunks) + { + return FALSE; + } + + + m_pChk_Head = l_pChunks; + m_pChk_Curs = m_pChk_Head + l_szUsed; //set current to new/old location + m_dwChk_Count += i_dwInc; + m_pChk_Tail = m_pChk_Head + m_dwChk_Count; + + return TRUE; +}// Inc_Chunks + + +//////////////////////////////////////////////////////////////////////////////// +//Is_VarArgs() +//Some processors have funny stack alignment rules, for example arm under 32 bits +//for 64 bits variables request 64 bit address stack alignment, some uses gen. +//registers, some changes order, etc. +tBOOL CP7Trace::Is_VarArgs(const CP7Trace::sStack_Desc *i_pDesc, ...) +{ + const tUINT8 *l_pData = (const tUINT8 *)&i_pDesc + sizeof(void*); + tBOOL l_bReturn = TRUE; + va_list l_pVal; + + va_start(l_pVal, i_pDesc); + while (1) + { + if (CP7Trace::sStack_Desc::eTypeU32 == i_pDesc->eType) + { + if (*(tUINT32*)l_pData != va_arg(l_pVal, tUINT32)) + { + l_bReturn = FALSE; + break; + } + + l_pData += SIZE_OF_ARG(tUINT32); + } + else if (CP7Trace::sStack_Desc::eTypeU64 == i_pDesc->eType) + { + if (*(tUINT64*)l_pData != va_arg(l_pVal, tUINT64)) + { + l_bReturn = FALSE; + break; + } + + l_pData += SIZE_OF_ARG(tUINT64); + } + else if (CP7Trace::sStack_Desc::eTypeD64 == i_pDesc->eType) + { + if (*(tDOUBLE*)l_pData != va_arg(l_pVal, tDOUBLE)) + { + l_bReturn = FALSE; + break; + } + + l_pData += SIZE_OF_ARG(tUINT64); + } + + if (i_pDesc->bLast) + { + break; + } + else + { + i_pDesc++; + } + } + + va_end(l_pVal); + + return l_bReturn; +} diff --git a/p7lib/Sources/Trace.h b/p7lib/Sources/Trace.h new file mode 100644 index 0000000..3e58865 --- /dev/null +++ b/p7lib/Sources/Trace.h @@ -0,0 +1,575 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// This file provide trace functionality / +//////////////////////////////////////////////////////////////////////////////// +#ifndef TRACE_H +#define TRACE_H + +#define P7TRACE_ITEM_BLOCK_ASTRING (-1) +#define P7TRACE_ITEM_BLOCK_USTRING16 (-2) +#define P7TRACE_ITEM_BLOCK_USTRING8 (-3) +#define P7TRACE_ITEM_BLOCK_USTRING32 (-4) +#define P7TRACE_ITEM_BLOCK_ASTRING_FIX (-5) +#define P7TRACE_ITEM_BLOCK_WSTRING_FIX (-6) + +#define P7TRACE_KEY_LENGTH (2) + +//#define P7TRACE_MAP_FILE_NAME L"Local\\P7Trace" +//#define P7TRACE_MAP_FILE_SIZE (sizeof(CP7Trace*) + sizeof(IP7_Client*)) + +#define P7TRACE_THREADS_POOL_SIZE (32) +#define P7TRACE_THREADS_MAX_SIZE (128) + +#define P7TRACE_MODULES_POOL_SIZE (32) +#define P7TRACE_MODULES_MAX_SIZE (512) +#define P7TRACE_MEMORY_ALIGNMENT (8) + + +//////////////////////////////////////////////////////////////////////////////// +//Memory manager, used for trace descriptions, avoid calling New & malloc +class CMemoryManager +{ +public: + enum eBuffer + { + eFileName, + eFunctionName, + eArguments, + eVaValues, + eCount + }; + +protected: + struct sBlock + { + void *pData; + sBlock *pNext; + }; + + struct sBuffer + { + void *pData; + size_t szBuffer; + }; + + sBlock *m_pCurrent; //dynamic, internal buffers - allocated once + size_t m_szCurrent; + size_t m_szCurrentUsed; + size_t m_szTotal; + size_t m_szMax; + size_t m_szRecommended; + sBlock *m_pBusy; + sBuffer m_pBuffers[CMemoryManager::eCount]; //static buffers, reusable + +public: + //////////////////////////////////////////////////////////////////////////// + //CMemoryManager + CMemoryManager(size_t i_szInitial, size_t i_szMax = 0xFFFFFFF) + : m_pCurrent(NULL) + , m_szCurrent(i_szInitial) + , m_szCurrentUsed(0) + , m_szTotal(i_szInitial) + , m_szMax(i_szMax) + , m_szRecommended(i_szInitial) + , m_pBusy(NULL) + { + memset(m_pBuffers, 0, sizeof(m_pBuffers)); + m_pCurrent = (sBlock*)malloc(m_szCurrent + sizeof(sBlock)); + if (m_pCurrent) + { + m_pCurrent->pData = (tUINT8*)m_pCurrent + sizeof(sBlock); + m_pCurrent->pNext = NULL; + } + }//CMemoryManager + + + //////////////////////////////////////////////////////////////////////////// + //~CMemoryManager + ~CMemoryManager() + { + while (m_pCurrent) + { + sBlock *l_pTmp = m_pCurrent; + m_pCurrent = m_pCurrent->pNext; + free(l_pTmp); + } + + while (m_pBusy) + { + sBlock *l_pTmp = m_pBusy; + m_pBusy = m_pBusy->pNext; + free(l_pTmp); + } + + for (size_t l_szI = 0; l_szI < LENGTH(m_pBuffers); l_szI++) + { + if (m_pBuffers[l_szI].pData) + { + free(m_pBuffers[l_szI].pData); + m_pBuffers[l_szI].pData = NULL; + } + } + }//~CMemoryManager + + //////////////////////////////////////////////////////////////////////////// + //Reuse - function is used for reusable temporary buffers + void *Reuse(CMemoryManager::eBuffer i_eBuffer, size_t i_szBuffer) + { + sBuffer *l_pBuffer = &m_pBuffers[i_eBuffer]; + + if ( (l_pBuffer->pData) + && (l_pBuffer->szBuffer >= i_szBuffer) + ) + { + return l_pBuffer->pData; + } + + size_t l_szNew = (i_szBuffer + (size_t)255) & (~(size_t)255); + void *l_pNew = realloc(l_pBuffer->pData, l_szNew); + if (l_pNew) + { + l_pBuffer->pData = l_pNew; + l_pBuffer->szBuffer = l_szNew; + } + + return l_pNew; + }//Reuse + + //////////////////////////////////////////////////////////////////////////// + //Size + size_t Size(CMemoryManager::eBuffer i_eBuffer) + { + return m_pBuffers[i_eBuffer].szBuffer; + }//Size + + //////////////////////////////////////////////////////////////////////////// + //Alloc - function is used for constant buffers used until class is a live + void *Alloc(size_t i_szBuffer) + { + tUINT8 *l_pReturn = NULL; + + i_szBuffer = (i_szBuffer + P7TRACE_MEMORY_ALIGNMENT - 1) & ~(P7TRACE_MEMORY_ALIGNMENT - 1); + + if ( (m_pCurrent) + && ((m_szCurrent - m_szCurrentUsed) >= i_szBuffer) + ) + { + l_pReturn = (tUINT8*)m_pCurrent->pData + m_szCurrentUsed; + m_szCurrentUsed += i_szBuffer; + } + else if ((m_szTotal + i_szBuffer) <= m_szMax) + { + //add current buffer to busy queue + m_pCurrent->pNext = m_pBusy; + m_pBusy = m_pCurrent; + + //allocate new buffer + m_szCurrentUsed = 0; + m_szCurrent = (i_szBuffer <= m_szRecommended) ? m_szRecommended : i_szBuffer; + m_pCurrent = (sBlock*)malloc(sizeof(sBlock) + m_szCurrent); + + if (m_pCurrent) + { + m_pCurrent->pData = (tUINT8*)m_pCurrent + sizeof(sBlock); + m_pCurrent->pNext = NULL; + l_pReturn = (tUINT8*)m_pCurrent->pData; + m_szCurrentUsed += i_szBuffer; + m_szTotal += m_szCurrent; + } + } + + return l_pReturn; + }//Alloc +}; + +//////////////////////////////////////////////////////////////////////////////// +//sData_Block +template +struct sData_Block +{ + tUINT32 dwCount; + tUINT32 dwUsed; + tData_Type *pData; + + sData_Block(tUINT32 i_dwCount) + : dwCount(i_dwCount) + , dwUsed(0) + , pData((tData_Type*)malloc(i_dwCount * sizeof(tData_Type))) + { + if (pData) + { + memset(pData, 0, i_dwCount * sizeof(tData_Type)); + } + } + + ~sData_Block() + { + if (pData) + { + free(pData); + pData = NULL; + } + + dwCount = 0; + dwUsed = 0; + } +};//sData_Block + + +//////////////////////////////////////////////////////////////////////////////// +//CP7Trace_Desc +class CP7Trace_Desc +{ + tUINT16 m_wID; + tUINT16 m_wModuleID; + //count of connections drops... see sP7C_Status. If this value and + //value from IP7_Client are different - it mean we loose connection + tUINT32 m_dwResets; + tUINT32 m_dwSize; + tUINT8 *m_pBuffer;//Buffer will contain sP7Trace_Format + + tINT32 *m_pBlocks; + tINT32 m_dwBlocks_Count; + sP7Trace_Arg *m_pArgs; + tUINT32 m_dwArgs_Count; + + tKeyType m_pKey[P7TRACE_KEY_LENGTH]; + + tBOOL m_bInitialized; +public: + CP7Trace_Desc(CMemoryManager &i_rMemory, + tUINT16 i_wID, + tUINT16 i_wLine, + tUINT16 i_wModuleID, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_pFormat, + tKeyType i_pKeys[P7TRACE_KEY_LENGTH], + tUINT32 i_dwFlags + ); + + CP7Trace_Desc(CMemoryManager &i_rMemory, + tUINT16 i_wID, + tUINT16 i_wLine, + tUINT16 i_wModuleID, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + tKeyType i_pKeys[P7TRACE_KEY_LENGTH] + ); + + ~CP7Trace_Desc() {} + + tBOOL Is_Initialized(); + tUINT8 *Get_Buffer(tUINT32 *o_pSize); + tINT32 *Get_Blocks(tUINT32 *o_pCount); + void Set_Resets(tUINT32 i_dwDrops); + tUINT32 Get_Resets(); + tUINT32 Get_Arguments_Count(); + const sP7Trace_Arg *Get_Arguments(tUINT32 &o_rCount); + tBOOL Is_Equal(tKeyType *i_pKey); + tBOOL Is_Greater(tKeyType *i_pKey); + + tUINT16 Get_ID(); + tUINT16 Get_MID(); +};//CP7Trace_Desc + + +//////////////////////////////////////////////////////////////////////////////// +//CDesc_Tree +class CDesc_Tree: + public CRBTree +{ +public: + //////////////////////////////////////////////////////////////////////////// + //~CDesc_Tree + virtual ~CDesc_Tree() + { + Clear(); + }//~CRBTree + +protected: + //////////////////////////////////////////////////////////////////////////// + virtual tBOOL Data_Release(CP7Trace_Desc* i_pData) + { + UNUSED_ARG(i_pData); + return TRUE; //memory used from pool, not necessary to return + }// Data_Release + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(tKeyType *i_pKey, CP7Trace_Desc *i_pData) + { + return i_pData->Is_Greater(i_pKey); + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(tKeyType *i_pKey, CP7Trace_Desc *i_pData) + { + return i_pData->Is_Equal(i_pKey); + } +};//CDesc_Tree + + + +//////////////////////////////////////////////////////////////////////////////// +//sModuleMap +struct sModuleMap +{ + sP7Trace_Module *pModule; + tXCHAR *pName; + + sModuleMap(const tXCHAR *i_pName, sP7Trace_Module *i_pModule) + : pModule(i_pModule) + , pName(PStrDub(i_pName)) + { + } + + ~sModuleMap() + { + if (pName) + { + PStrFreeDub(pName); + pName = NULL; + } + + pModule = NULL; + } +};//sModuleMap + + +//////////////////////////////////////////////////////////////////////////////// +//CModules_Tree +class CModules_Tree: + public CRBTree +{ +public: + CModules_Tree() + : CRBTree(16, TRUE) + { + } + +protected: + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey < i_pData::key) + //FALSE - otherwise + tBOOL Is_Key_Less(const tXCHAR *i_pKey, sModuleMap *i_pData) + { + return (0 < PStrCmp(i_pKey, i_pData->pName)) ? TRUE : FALSE; + } + + //////////////////////////////////////////////////////////////////////////// + //Return + //TRUE - if (i_pKey == i_pData::key) + //FALSE - otherwise + tBOOL Is_Qual(const tXCHAR *i_pKey, sModuleMap *i_pData) + { + return (0 == PStrCmp(i_pKey, i_pData->pName)) ? TRUE : FALSE; + } +};//CModules_Tree + + +//////////////////////////////////////////////////////////////////////////////// +#define P7_TRACE_DESC_HARDCODED_COUNT (1024) + + +class CP7Trace + : public IP7_Trace +{ + struct sStack_Desc + { + enum eType + { + eTypeU32, + eTypeU64, + eTypeD64 + }; + + union uVal + { + tUINT32 dw32; + tUINT64 dw64; + tDOUBLE db64; + }; + + CP7Trace::sStack_Desc::uVal uValue; + CP7Trace::sStack_Desc::eType eType; + tBOOL bLast; + }; + + typedef sData_Block sThreadsR; //running threads + typedef sData_Block sThreadsS; //stopped threads + typedef sData_Block sModules; //modules + + + //put volatile variables at the top, to obtain 32 bit alignment. + //Project has 8 bytes alignment by default + tINT32 volatile m_lReference; + tUINT32 m_dwSequence; + + IP7_Client *m_pClient; + tUINT32 m_dwChannel_ID; + CP7Trace_Desc *m_pDesc_Array[P7_TRACE_DESC_HARDCODED_COUNT]; + CDesc_Tree m_cDescU_Tree; + CDesc_Tree m_cDescM_Tree; + tUINT16 m_wDesc_Tree_ID; + + tLOCK m_sCS; + tUINT32 m_dwLast_ID; + tBOOL m_bInitialized; + tBOOL m_bActive; + eP7Trace_Level m_eVerbosity; + + sP7Trace_Info m_sHeader_Info; + sP7Trace_Data m_sHeader_Data; + sP7Trace_Utc_Offs m_sHeader_Utc; + + sP7C_Status m_sStatus; + + sP7C_Data_Chunk *m_pChk_Head; + sP7C_Data_Chunk *m_pChk_Tail; + sP7C_Data_Chunk *m_pChk_Curs; + tUINT32 m_dwChk_Count; + tUINT32 m_dwChk_Size; + + tBOOL m_bIs_Channel; + tUINT32 m_dwFlags; + + CAList m_cThreadsR; + CAList m_cThreadsS; + + tUINT16 m_wLast_ModuleID; + CAList m_cModules; + CModules_Tree m_cModules_Map; + + CShared::hShared m_hShared; + CMemoryManager m_cMemory; + + tUINT8 *m_pVargs; + size_t m_szVargs; + + tUINT8 m_pExtensions[4]; + + stTrace_Conf m_sConf; + +public: + CP7Trace(IP7_Client *i_pClient, + const tXCHAR *i_pName, + const stTrace_Conf *i_pConf); //for arguments description see P7_Client.h + virtual ~CP7Trace(); + + tBOOL Is_Initialized(); + + IP7C_Channel::eType Get_Type() { return IP7C_Channel::eTrace; } + void On_Init(sP7C_Channel_Info *i_pInfo); + void On_Receive(tUINT32 i_dwChannel, tUINT8 *i_pBuffer, tUINT32 i_dwSize, tBOOL i_bBigEndian); + void On_Status(tUINT32 i_dwChannel, const sP7C_Status *i_pStatus); + void On_Flush(tUINT32 i_dwChannel, tBOOL *io_pCrash); + + tBOOL Register_Thread(const tXCHAR *i_pName, tUINT32 i_dwThreadId); + tBOOL Unregister_Thread(tUINT32 i_dwThreadId); + + tBOOL Register_Module(const tXCHAR *i_pName, IP7_Trace::hModule *o_hModule); + + void Set_Verbosity(IP7_Trace::hModule i_hModule, eP7Trace_Level i_eVerbosity); + eP7Trace_Level Get_Verbosity(IP7_Trace::hModule i_hModule); + + + tBOOL Trace(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR *i_pFormat, + ... + ); + + tBOOL Trace_Embedded(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat + ); + + tBOOL Trace_Embedded(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ); + + tBOOL Trace_Managed(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const tXCHAR *i_pFile, + const tXCHAR *i_pFunction, + const tXCHAR *i_pMessage + ); + + virtual tINT32 Add_Ref() + { + return ATOMIC_INC(&m_lReference); + } + + virtual tINT32 Release() + { + tINT32 l_lResult = ATOMIC_DEC(&m_lReference); + if ( 0 >= l_lResult ) + { + delete this; + } + + return l_lResult; + } + + tBOOL Share(const tXCHAR *i_pName); + +private: + void Flush(); + + tBOOL Trace_Raw(tUINT16 i_wTrace_ID, + eP7Trace_Level i_eLevel, + IP7_Trace::hModule i_hModule, + tUINT16 i_wLine, + const char *i_pFile, + const char *i_pFunction, + tKeyType *i_pKey, + const tXCHAR **i_ppFormat, + va_list *i_pVa_List + ); + + tBOOL Inc_Chunks(tUINT32 i_dwInc); + + tBOOL Is_VarArgs(const CP7Trace::sStack_Desc *i_pDesc, ...); +}; + +#endif //TRACE_H diff --git a/p7lib/Sources/resource.h b/p7lib/Sources/resource.h new file mode 100644 index 0000000..4db98f7 --- /dev/null +++ b/p7lib/Sources/resource.h @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by P7Client.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/p7lib/Sources/targetver.h b/p7lib/Sources/targetver.h new file mode 100644 index 0000000..462b9fa --- /dev/null +++ b/p7lib/Sources/targetver.h @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +// / +// 2012-2020 (c) Baical / +// / +// This library is free software; you can redistribute it and/or / +// modify it under the terms of the GNU Lesser General Public / +// License as published by the Free Software Foundation; either / +// version 3.0 of the License, or (at your option) any later version. / +// / +// This library is distributed in the hope that it will be useful, / +// but WITHOUT ANY WARRANTY; without even the implied warranty of / +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / +// Lesser General Public License for more details. / +// / +// You should have received a copy of the GNU Lesser General Public / +// License along with this library. / +// / +//////////////////////////////////////////////////////////////////////////////// +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/p7lib/Tests/CMakeLists.txt b/p7lib/Tests/CMakeLists.txt new file mode 100644 index 0000000..f4f9deb --- /dev/null +++ b/p7lib/Tests/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(Speed) +add_subdirectory(Trace) \ No newline at end of file diff --git a/p7lib/Tests/Speed/CMakeLists.txt b/p7lib/Tests/Speed/CMakeLists.txt new file mode 100644 index 0000000..35a624d --- /dev/null +++ b/p7lib/Tests/Speed/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +project(p7_speed_test) + +if(WIN32) +elseif(UNIX) +else() + message(FATAL_ERROR "${PROJECT_NAME}: Platform not supported") +endif() + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} PROJ_SOURCES) +add_executable(${PROJECT_NAME} ${PROJ_SOURCES}) +target_link_libraries (${PROJECT_NAME} p7) + +set_ide_folder(${PROJECT_NAME}) + +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) + + + diff --git a/p7lib/Tests/Speed/Speed.cpp b/p7lib/Tests/Speed/Speed.cpp new file mode 100644 index 0000000..4adf0d6 --- /dev/null +++ b/p7lib/Tests/Speed/Speed.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +#include +#include + + +#include "GTypes.h" + +#include "PLock.h" +#include "PTime.h" +#include "PThreadShell.h" +#include "Ticks.h" +#include "UTF.h" +#include "AList.h" +#include "PString.h" +#include "PProcess.h" +#include "PConsole.h" + +#include "P7_Client.h" +#include "P7_Trace.h" + + +tBOOL Print2Buffer(char *o_pBuffer, + const char *i_pFormat, + ... + ) +{ + if ( (NULL == o_pBuffer) + || (NULL == i_pFormat) + ) + { + return FALSE; + } + + va_list arglist; + va_start(arglist, i_pFormat); + vsprintf(o_pBuffer, i_pFormat, arglist); + va_end(arglist); + + return TRUE; +} + + +#define ITERATIONS_COUNT (100000) + + +int main(int i_iArgC, char* i_pArgV[]) +{ + UNUSED_ARG(i_iArgC); + UNUSED_ARG(i_pArgV); + + printf("This test measures the time it is necessary for:\n"); + printf(" 1. print %d times simple string to buffer\n", ITERATIONS_COUNT); + printf(" 2. print %d times simple string to console\n", ITERATIONS_COUNT); + printf(" this test combine test #1 and console printing\n"); + printf(" 3. print & deliver %d times simple string to trace server\n", ITERATIONS_COUNT); + printf(" server will receive:\n"); + printf(" * Text message\n"); + printf(" * Level (error, warning, .. etc)\n"); + printf(" * Time with 100ns granularity\n"); + printf(" * Current thread ID\n"); + printf(" * Current module ID\n"); + printf(" * Current processor number\n"); + printf(" * Function name\n"); + printf(" * File name\n"); + printf(" * File line number\n"); + printf(" * Sequence number\n"); + printf("*************************************************************************\n"); + printf("Press ENTER to start ....\n"); + + Get_Char(); + + tUINT64 l_qwTime = 0; + tUINT64 l_qwTime_1 = 0; + tUINT64 l_qwTime_2 = 0; + tUINT64 l_qwTime_3 = 0; + + //////////////////////////////////////////////////////////////////////////// + //Test 1 + char l_pText[4096]; + l_qwTime = GetPerformanceCounter(); + + for (tUINT32 l_dwI = 0; l_dwI < ITERATIONS_COUNT; l_dwI ++) + { + Print2Buffer(l_pText, "[%s][%s][%d][%d][%d] Test format string, iteration is %d", + __FILE__, + __FUNCTION__, + __LINE__, + CProc::Get_Thread_Id(), + CProc::Get_Processor(), + l_dwI); + } + + l_qwTime_1 = (GetPerformanceCounter() - l_qwTime) / (GetPerformanceFrequency() / 1000ull); + + + //////////////////////////////////////////////////////////////////////////// + //Test 2 + l_qwTime = GetPerformanceCounter(); + + for (tUINT32 l_dwI = 0; l_dwI < ITERATIONS_COUNT; l_dwI ++) + { + printf(l_pText, "[%s][%s][%d][%d][%d] Test format string, iteration is %d", + __FILE__, + __FUNCTION__, + __LINE__, + CProc::Get_Thread_Id(), + CProc::Get_Processor(), + l_dwI + ); + } + + l_qwTime_2 = (GetPerformanceCounter() - l_qwTime) / (GetPerformanceFrequency() / 1000ull); + + + //////////////////////////////////////////////////////////////////////////// + //Test 3 + IP7_Client *l_pClient = P7_Create_Client(TM("/P7.PSize=1472 /P7.Pool=65536")); + IP7_Trace *l_pTrace = P7_Create_Trace(l_pClient, TM("Speed Test")); + + if ( (l_pClient) + && (l_pTrace) + ) + { + l_qwTime = GetPerformanceCounter(); + + for (tUINT32 l_dwI = 0; l_dwI < ITERATIONS_COUNT; l_dwI ++) + { + l_pTrace->P7_QTRACE(1, 0, TM("Test format string, iteration is %d"), l_dwI); + } + + l_qwTime_3 = (GetPerformanceCounter() - l_qwTime) / (GetPerformanceFrequency() / 1000ull); + } + + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + + printf("\n*****************************************************************\n"); + printf("Test results:\n"); + + + + printf(" Test 1 (to buffer) duration: %d ms, %d per second\n", + (tUINT32)l_qwTime_1, + (tUINT32)((1000.0 / (tDOUBLE)l_qwTime_1) * (tDOUBLE)ITERATIONS_COUNT) + ); + printf(" Test 2 (to console) duration: %d ms, %d per second\n", + (tUINT32)l_qwTime_2, + (tUINT32)((1000.0 / (tDOUBLE)l_qwTime_2) * (tDOUBLE)ITERATIONS_COUNT) + ); + printf(" Test 3 (to P7 trace) duration: %d ms, %d per second\n", + (tUINT32)l_qwTime_3, + (tUINT32)((1000.0 / (tDOUBLE)l_qwTime_3) * (tDOUBLE)ITERATIONS_COUNT) + ); + + return 0; +} + diff --git a/p7lib/Tests/Trace/CMakeLists.txt b/p7lib/Tests/Trace/CMakeLists.txt new file mode 100644 index 0000000..c60b789 --- /dev/null +++ b/p7lib/Tests/Trace/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.0 FATAL_ERROR) + +project(p7_tests) + +if(WIN32) +elseif(UNIX) +else() + message(FATAL_ERROR "${PROJECT_NAME}: Platform not supported") +endif() + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} PROJ_SOURCES) +add_executable(${PROJECT_NAME} ${PROJ_SOURCES}) +target_link_libraries (${PROJECT_NAME} p7) + +set_ide_folder(${PROJECT_NAME}) + +install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin) + + + diff --git a/p7lib/Tests/Trace/Main.cpp b/p7lib/Tests/Trace/Main.cpp new file mode 100644 index 0000000..b442c7e --- /dev/null +++ b/p7lib/Tests/Trace/Main.cpp @@ -0,0 +1,2057 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "GTypes.h" + +#include "Length.h" + +#include "PAtomic.h" +#include "PLock.h" +#include "PString.h" +#include "PTime.h" +#include "IMEvent.h" +#include "PMEvent.h" +#include "PThreadShell.h" +#include "CRC32.h" +#include "RBTree.h" +#include "AList.h" + +#include "Ticks.h" +#include "PString.h" +#include "WString.h" +#include "PFileSystem.h" +#include "PConsole.h" + +#include "UTF.h" +#include "PProcess.h" +#include "IJournal.h" +#include "PJournal.h" + +#include "P7_Client.h" +#include "P7_Trace.h" +#include "P7_Telemetry.h" +#include "P7_Extensions.h" + + +#if !defined(UINTMAX_MAX) + typedef uint64_t uintmax_t; + #define UINTMAX_MAX 0xffffffffffffffffU +#endif + +#if !defined(INTMAX_MAX) + typedef int64_t intmax_t; + #define INTMAX_MIN (-0x7fffffffffffffff - 1) + #define INTMAX_MAX 0x7fffffffffffffff +#endif + + +#if defined(_MSC_VER) + + #pragma warning(disable : 4267) + #pragma warning(disable : 4995) + #pragma warning(disable : 4996) + //allow to see dump of memory leaks at the end of test in VS debug output + #define _CRTDBG_MAP_ALLOC + #include + + #define DUMP_MEMORY_LEAKS() _CrtDumpMemoryLeaks() + #define SPRINTF swprintf + #define STRNICMP strnicmp + +#elif defined (__GNUC__) + + #define DUMP_MEMORY_LEAKS() printf("memory leaks detection is missing !") + #define SPRINTF sprintf + #define STRNICMP strncasecmp + +#endif + + + +#define TEST_HELP "/?" +#define TEST_NUMBER "/Test=" + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 1 // +//////////////////////////////////////////////////////////////////////////////// +// Here we made simple test Create and destroy P7 client and P7 trace // +// and using shared objects for P7 client & trace // +//////////////////////////////////////////////////////////////////////////////// + +#define TEST_01_COUNT "/Count=" +#define TEST_01_P7_TRACE_SHARE_NAME TM("P7.Trace.Share") +#define TEST_01_P7_CLIENT_SHARE_NAME TM("P7.Share") + + +//////////////////////////////////////////////////////////////////////////////// +//Test_01 +int Test_01(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + IP7_Client *l_pClientS = NULL; + IP7_Trace *l_pTrace = NULL; + IP7_Trace::hModule l_hModule = NULL; + IP7_Trace *l_pTraceS = NULL; + tUINT32 l_dwCount = 1000; + tXCHAR l_pChannel[128]; + tBOOL l_bError = FALSE; + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test create and destroy P7 client and P7 trace in loop\n"); + printf("Command line arguments:\n"); + printf("/Count : Count iterations\n"); + printf(" Default value - 1000, min 100, max - uint32\n"); + printf(" Example: /Count=10000\n"); + goto l_lExit; + } + else if (0 == STRNICMP(i_pArgV[l_iI], TEST_01_COUNT, LENGTH(TEST_01_COUNT)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_01_COUNT)-1, "%u", &l_dwCount); + if (10 > l_dwCount) + { + l_dwCount = 10; + } + } + } + + printf("Start: Iterations count %d\n", l_dwCount); + + for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI++) + { + printf("Iteration = %d\n", l_dwI); + + l_pClient = P7_Create_Client(NULL); + + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized. Iteration = %d, Exit\n", l_dwI); + l_bError = TRUE; + } + else + { + l_pClient->Share(TEST_01_P7_CLIENT_SHARE_NAME); + l_pClientS = P7_Get_Shared(TEST_01_P7_CLIENT_SHARE_NAME); + + if (l_pClientS) + { + l_pClient->Release(); + l_pClient = l_pClientS; + l_pClientS = NULL; + } + else + { + printf("Error: P7_Get_Shared failed. Iteration = %d\n", l_dwI); + } + + + for (tUINT32 l_dwJ = 0; l_dwJ < 2; l_dwJ++) + { + SPRINTF(l_pChannel, TM("Chanel[%03d - %02d]"), l_dwI, l_dwJ); + l_pTrace = P7_Create_Trace(l_pClient, l_pChannel); + + if (l_pTrace) + { + if (!l_pTrace->Register_Thread(TM("Application"), 0)) + { + printf("Error: Register_Thread failed. Iteration = %d\n", l_dwJ); + } + + if (!l_pTrace->Register_Module(TM("Test #1"), &l_hModule)) + { + printf("Error: Register_Module failed. Iteration = %d\n", l_dwJ); + } + + for (tUINT32 l_dwK = 0; l_dwK < 2000; l_dwK ++) + { + l_pTrace->P7_INFO(l_hModule, TM("Iteration %d"), l_dwK); + } + + if (l_pTrace->Share(TEST_01_P7_TRACE_SHARE_NAME)) + { + l_pTraceS = P7_Get_Shared_Trace(TEST_01_P7_TRACE_SHARE_NAME); + if (l_pTraceS) + { + if (!l_pTraceS->Register_Module(TM("Test #1"), &l_hModule)) + { + printf("Error: Register_Module failed. Iteration = %d\n", l_dwJ); + } + + for (tUINT32 l_dwK = 0; l_dwK < 2000; l_dwK ++) + { + l_pTraceS->P7_INFO(l_hModule, TM("Share: Iteration %d"), l_dwK); + } + + l_pTraceS->Release(); + } + } + + if (!l_pTrace->Unregister_Thread(0)) + { + printf("Error: Unregister_Thread() failed\n"); + } + + l_pTrace->Release(); + l_pTrace = NULL; + + CThShell::Sleep(50); + } + else + { + printf("Error: P7_Create_Trace failed. Iteration = %d, Exit\n", l_dwI); + l_bError = TRUE; + } + } + + l_pClient->Release(); + l_pClient = NULL; + } + + if (l_bError) + { + break; + } + } + +l_lExit: + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_01 + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 2 // +//////////////////////////////////////////////////////////////////////////////// +// Here we check ability of few P7 trace to work in parallel // +//////////////////////////////////////////////////////////////////////////////// + +#define TEST_02_CHANNELS_COUNT_MAX (10) + +//from 1(~1000 traces per second) to 10(~10 000 traces per second) +#define TEST_02_SPEED_MAX (10) + + +#define TEST_02_CONSOLE_ARG_COUNT "/Count=" +#define TEST_02_CONSOLE_ARG_SPEED "/Speed=" +#define TEST_02_CONSOLE_ARG_DURATION "/Duration=" + + +struct sTest_02_Thread +{ + IP7_Client *pClient; + IMEvent *iEvent; + tUINT32 dwIndex; + tUINT32 dwSpeed; + CThShell::tTHREAD hThread; + tBOOL bThread; +}; + + +//////////////////////////////////////////////////////////////////////////////// +//Test_02_Embedded_Trace +static void Test_02_Embedded_Trace(IP7_Trace *i_pTrace, + IP7_Trace::hModule i_hModule, + const tXCHAR *i_pFormat, + ... + ) +{ + if (i_pTrace) + { + va_list l_pVl; + va_start(l_pVl, i_pFormat); + i_pTrace->Trace_Embedded(0, + EP7TRACE_LEVEL_INFO, + i_hModule, + (tUINT16)__LINE__, + __FILE__, + __FUNCTION__, + &i_pFormat, + &l_pVl + ); + va_end(l_pVl); + } +}//Test_02_Embedded_Trace + + +//////////////////////////////////////////////////////////////////////////////// +//Test_02_Routine +static THSHELL_RET_TYPE THSHELL_CALL_TYPE Test_02_Routine(void *i_pContext) +{ + sTest_02_Thread *l_pParam = (sTest_02_Thread*)i_pContext; + const size_t l_szModules = 16; + IP7_Trace::hModule l_hModules[l_szModules] = {}; + IP7_Trace *l_pTrace = NULL; + tUINT32 l_dwSent = 0; + tUINT32 l_dwRejected = 0; + tUINT64 l_qwIDX = 0; + tUINT32 l_dwTime = GetTickCount(); + tXCHAR l_pName[256]; + + if (NULL == l_pParam) + { + printf("Error: thread input parameter is NULL\n"); + return 0; + } + + SPRINTF(l_pName, TM("Trace Channel %d"), l_pParam->dwIndex); + + l_pTrace = P7_Create_Trace(l_pParam->pClient, l_pName); + + if (NULL == l_pTrace) + { + printf("Thread %d: Error: P7_Create_Trace() failed\n", l_pParam->dwIndex); + return 0; + } + + for (size_t l_szI = 0; l_szI < l_szModules; l_szI++) + { + SPRINTF(l_pName, TM("Module #%d:%d"), l_pParam->dwIndex, (int)l_szI); + if (!l_pTrace->Register_Module(l_pName, &l_hModules[l_szI])) + { + printf("Thread %d: Error: Register_Module() failed\n", l_pParam->dwIndex); + } + } + + SPRINTF(l_pName, TM("Thread #%d"), l_pParam->dwIndex); + if (!l_pTrace->Register_Thread(l_pName, 0)) + { + printf("Thread %d: Error: Register_Thread() failed\n", l_pParam->dwIndex); + } + + l_pTrace->Set_Verbosity(NULL, EP7TRACE_LEVEL_TRACE); + + Test_02_Embedded_Trace(l_pTrace, + l_hModules[0], + TM("Create thread %X"), + CProc::Get_Thread_Id() + ); + + while (MEVENT_TIME_OUT == l_pParam->iEvent->Wait(10)) + { + for (tUINT32 l_dwI = 0; l_dwI < 10 * l_pParam->dwSpeed; l_dwI++) + { + l_qwIDX++; + if (l_pTrace->P7_QTRACE(1, + l_hModules[(size_t)l_qwIDX % l_szModules], + TM("Test 1[%I64d] %d, %d, %s %d"), + l_qwIDX, + 10, + 20, + TM("Ups01"), + l_dwSent + ) + ) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + + if (0 == (l_qwIDX % 10)) + { + l_qwIDX ++; + if (l_pTrace->P7_DEBUG(l_hModules[(size_t)l_qwIDX % l_szModules], TM("Debug message(3) %s %d, %I64d"), TM("P7_DEBUG"), l_dwSent, l_qwIDX)) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + + if (0 == (l_qwIDX % 22)) + { + l_qwIDX ++; + if (l_pTrace->P7_INFO(l_hModules[(size_t)l_qwIDX % l_szModules], TM("Info message(1) %s"), TM("P7_INFO"))) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + + if (0 == (l_qwIDX % 153)) + { + l_qwIDX ++; + if (l_pTrace->P7_WARNING(l_hModules[(size_t)l_qwIDX % l_szModules], TM("Warning message(1) %d"), l_dwSent)) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + + + if (0 == (l_qwIDX % 155)) + { + l_qwIDX ++; + if (l_pTrace->P7_ERROR(l_hModules[(size_t)l_qwIDX % l_szModules], TM("ERROR message(2) %I64d, %s"), l_qwIDX, TM("P7_ERROR"))) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + }//for (tUINT32 l_dwI = 0; l_dwI < 10 * TEST_SPEED; l_dwI++) + + + if (CTicks::Difference(GetTickCount(), l_dwTime) >= 1000) + { + printf("Thread %d: Traces %d (%d) / %d ms\n", + l_pParam->dwIndex, + l_dwSent, + l_dwRejected, + CTicks::Difference(GetTickCount(), l_dwTime) + ); + l_dwTime = GetTickCount(); + l_dwSent = 0; + l_dwRejected = 0; + } + }//while (WAIT_TIMEOUT == WaitForSingleObject(g_pEvent_Exit, 10)) + + Test_02_Embedded_Trace(l_pTrace, + l_hModules[0], + TM("Leave thread %X"), + CProc::Get_Thread_Id() + ); + + l_pTrace->P7_CRITICAL(l_hModules[0], TM("All done, bye bye"), 0); + + if (!l_pTrace->Unregister_Thread(0)) + { + printf("Error: Unregister_Thread() failed\n"); + } + + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + CThShell::Cleanup(); + + return THSHELL_RET_OK; +}//Test_02_Routine + + +//////////////////////////////////////////////////////////////////////////////// +//Test_02 +int Test_02(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + tBOOL l_bExit = FALSE; + tUINT32 l_dwCount = 1; + tUINT32 l_dwSpeed = 1; + tUINT32 l_dwDuration = 0; + tUINT32 l_dwStart = GetTickCount(); + CMEvent *l_pEvent = NULL; + sTest_02_Thread l_pThreads[TEST_02_CHANNELS_COUNT_MAX]; + + memset(l_pThreads, 0, sizeof(l_pThreads)); + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test create one P7 client and defined by user amount of threads\n"); + printf("each thread create own P7 Trace object and start sending traces with\n"); + printf("defined by used speed\n"); + printf("Command line arguments:\n"); + printf("/Count : Count of simultaneously opened streams\n"); + printf(" Default value - 2, min 1, max 10\n"); + printf(" Example: /Count=10\n"); + printf("/Speed : Delivery Speed, min 1, max 10000\n"); + printf(" Default value - 1\n"); + printf(" Example: /Speed=5\n"); + printf("/Duration : Working duration in seconds\n"); + printf(" Default value is 0 - infinite\n"); + printf(" Example: /Duration=20\n"); + printf("/P7.Help : P7 engine command line help\n"); + goto l_lExit; + } + else if (0 == STRNICMP(i_pArgV[l_iI], TEST_02_CONSOLE_ARG_COUNT, LENGTH(TEST_02_CONSOLE_ARG_COUNT)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_02_CONSOLE_ARG_COUNT)-1, "%u", &l_dwCount); + if ( (1 > l_dwCount) + || (10 < l_dwCount) + ) + { + l_dwCount = 2; + } + } + else if (0 == STRNICMP(i_pArgV[l_iI], TEST_02_CONSOLE_ARG_SPEED, LENGTH(TEST_02_CONSOLE_ARG_SPEED)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_02_CONSOLE_ARG_SPEED)-1, "%u", &l_dwSpeed); + if ( (1 > l_dwSpeed) + || (10000 < l_dwSpeed) + ) + { + l_dwSpeed = 1; + } + } + else if (0 == STRNICMP(i_pArgV[l_iI], TEST_02_CONSOLE_ARG_DURATION, LENGTH(TEST_02_CONSOLE_ARG_DURATION)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_02_CONSOLE_ARG_DURATION)-1, "%u", &l_dwDuration); + } + } + + l_pClient = P7_Create_Client(NULL); + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized. Exit\n"); + goto l_lExit; + } + + l_pEvent = new CMEvent(); + + if ( (NULL == l_pEvent) + || (FALSE == l_pEvent->Init(1, EMEVENT_SINGLE_MANUAL)) + ) + { + printf("Error: Event was not created\n"); + goto l_lExit; + } + + printf("Start: Duration %d, Delivery speed %d, Channels count %d. Press Esc to exit\n", + l_dwDuration, + l_dwSpeed, + l_dwCount + ); + + for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI++) + { + l_pThreads[l_dwI].dwIndex = l_dwI; + l_pThreads[l_dwI].pClient = l_pClient; + l_pThreads[l_dwI].dwSpeed = l_dwSpeed; + l_pThreads[l_dwI].iEvent = l_pEvent; + l_pThreads[l_dwI].bThread = TRUE; + + if (FALSE == CThShell::Create(&Test_02_Routine, + &l_pThreads[l_dwI], + &l_pThreads[l_dwI].hThread, + TM("Test 02") + ) + ) + { + l_pThreads[l_dwI].bThread = FALSE; + printf("Failed to create thread\n"); + } + } + + while (FALSE == l_bExit) + { + CThShell::Sleep(500); + + if ( (Is_Key_Hit()) + && (27 == Get_Char()) + ) + { + printf("Esc ... exiting\n"); + l_bExit = TRUE; + } + + if ( (l_dwDuration) + && (CTicks::Difference(GetTickCount(), l_dwStart) >= (l_dwDuration * 1000)) + ) + { + printf("Working time is expired ... exiting\n"); + l_bExit = TRUE; + } + } + + l_pEvent->Set(0); + +l_lExit: + + for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI++) + { + if (l_pThreads[l_dwI].bThread) + { + if (FALSE == CThShell::Close(l_pThreads[l_dwI].hThread, 60000)) + { + printf("ERROR: thread %d timeout !\n", l_dwI); + } + } + } + + if (l_pEvent) + { + delete l_pEvent; + l_pEvent = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_02 + + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 3 // +//////////////////////////////////////////////////////////////////////////////// +// Here we check ability of few P7 trace to work with different formats // +//////////////////////////////////////////////////////////////////////////////// + +#define TEST_03_COUNT "/Count=" + +//////////////////////////////////////////////////////////////////////////////// +//Test_03 +int Test_03(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + tBOOL l_bExit = FALSE; + tUINT32 l_dwCount = 1; + IP7_Trace *l_pTrace = NULL; + IP7_Trace::hModule l_hModule = NULL; + const tXCHAR *l_pName = TM("Formats test"); + + UNUSED_ARG(l_bExit); + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test create one P7 client and one P7.Trace for sending\n"); + printf("different traces with all possible argument's formats\n"); + printf("Command line arguments:\n"); + printf("/Count : Count iterations\n"); + printf(" Default value - 1, min 1, max - uint32\n"); + printf(" Example: /Count=10000\n"); + goto l_lExit; + } + else if (0 == STRNICMP(i_pArgV[l_iI], TEST_03_COUNT, LENGTH(TEST_03_COUNT)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_01_COUNT) - 1, "%u", &l_dwCount); + if (1 > l_dwCount) + { + l_dwCount = 1; + } + } + } + + + l_pClient = P7_Create_Client(NULL); + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized. Exit\n"); + goto l_lExit; + } + + l_pTrace = P7_Create_Trace(l_pClient, l_pName); + if (NULL == l_pClient) + { + printf("Error: P7.Trace engine was not initialized. Exit\n"); + goto l_lExit; + } + + + if (!l_pTrace->Register_Module(TM("Test #3"), &l_hModule)) + { + printf("Error: Register_Module() failed\n"); + } + + + if (!l_pTrace->Register_Thread(TM("Application"), 0)) + { + printf("Error: Register_Thread() failed\n"); + } + + for (tUINT32 l_iI = 0; l_iI < l_dwCount; l_iI++) + { + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Strings test"), 0); + l_pTrace->P7_INFO(l_hModule, + TM("String: %s (%%s = 12345 abcde .. z // \\ ABCDE .. Z)"), + TM("12345 abcde .. z // \\ ABCDE .. Z") + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %.*s (%%.*s = ([x]s is unsupported by P7))"), + 0, TM("12345 abcde .. z // \\ ABCDE .. Z") + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %ls (%%ls = 12345 abcde .. z // \\ ABCDE .. Z)"), + L"12345 abcde .. z // \\ ABCDE .. Z" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %.10ls (%%.10ls = ([x]s is unsupported by P7))"), + L"12345 abcde .. z // \\ ABCDE .. Z" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %hs (%%hs = 12345 abcde .. z // \\ ABCDE .. Z)"), + "12345 abcde .. z // \\ ABCDE .. Z" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %.10hs (%%.10hs = ([x]s is unsupported by P7))"), + "12345 abcde .. z // \\ ABCDE .. Z" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %ws (%%ws = 12345 abcde .. z // \\ ABCDE .. Z)"), + TM("12345 abcde .. z // \\ ABCDE .. Z") + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %.10ws (%%.10ws = ([x]s is unsupported by P7))"), + TM("12345 abcde .. z // \\ ABCDE .. Z") + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %hS (%%hS = 12345 abcde .. z // \\ ABCDE .. Z)"), + "12345 abcde .. z // \\ ABCDE .. Z" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %.*hS (%%.*hS = ([x]s is unsupported by P7))"), + 10, "12345 abcde .. z // \\ ABCDE .. Z" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %s (%%s = NULL)"), + NULL + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %.10s (%%.10s = ([x]s is unsupported by P7))"), + NULL + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %hs (%%hs = NULL)"), + NULL + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %ls (%%ls = NULL)"), + NULL + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %s (%%s = \"\")"), + TM("") + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %hs (%%hs = \"\")"), + "" + ); + + l_pTrace->P7_INFO(l_hModule, + TM("String: %ls (%%ls = \"\")"), + L"" + ); + + + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Characters test"), 0); + + l_pTrace->P7_INFO(l_hModule, + TM("Char: %c (%%c = G)"), + TM('G') + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Char: %hc (%%hc = G)"), + 'G' + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Char: %C (%%C = F)"), + 'F' + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Char: %hC (%%hC = R)"), + 'R' + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Char: %lc (%%lc = S)"), + TM('S') + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Char: %wc (%%wc = Z)"), + TM('Z') + ); + + + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Integer values"), 0); + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %d (%%d = 1234567890) | %i (%%i = 1234567890) | %u (%%u = 1234567890) "), + (tINT32)1234567890, + (tINT32)1234567890, + (tUINT32)1234567890 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %jd (%%jd = 1234567890) | %ji (%%ji = 1234567890) | %ju (%%ju = 1234567890) "), + (intmax_t)1234567890, + (intmax_t)1234567890, + (uintmax_t)1234567890 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Octal %o (%%o = 11145401322) | Octal %jo (%%jo = 11145401322)"), + (tUINT32)1234567890, + (uintmax_t)1234567890 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %x (%%x = 499602d2) | %X (%%X = 499602D2), %jX (%%jX = 499602D2)"), + (tUINT32)1234567890, + (tUINT32)1234567890, + (uintmax_t)1234567890 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %ld (%%ld = 1234567890) | %li (%%li = 1234567890) | %lu (%%lu = 1234567890) "), + (long int)1234567890, + (long int)1234567890, + (unsigned long int)1234567890 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Octal %lo (%%lo = 11145401322)"), + (unsigned long int)1234567890 + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %lx (%%lx = 499602d2) | %lX (%%lX = 499602D2)"), + (unsigned long int)1234567890, + (unsigned long int)1234567890 + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %lld (%%lld = 1234567890987) | %lli (%%lli = 1234567890987ULL)"), + (tINT64)1234567890987ULL, + (tINT64)1234567890987ULL + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Octal %llo (%%llo = 21756176604053ULL)"), + (tUINT64)1234567890987ULL + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %llx (%%llx = ffaabbccee12) | %llX (%%llX = FFAABBCCEE12)"), + (tUINT64)0xffaabbccee12ULL, + (tUINT64)0xFFAABBCCEE12ULL + ); + + + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %hd (%%hd = 32700) | %hi (%%hi = 32700) | %hu (%%hu = 65500) "), + (tINT16)32700, + (tINT16)32700, + (tUINT16)65500 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Octal %ho (%%ho = 77674)"), + (tUINT16)32700 + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %hx (%%hx = AABB) | %hX (%%hX = AABB)"), + (tUINT16)0xAABB, + (tUINT16)0xAABB + ); + + + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %I32d (%%I32d = 1234567890) | %I32i (%%I32i = 1234567890) | %I32u (%%I32u = 1234567890) "), + (tINT32)1234567890, + (tINT32)1234567890, + (tUINT32)1234567890 + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Octal %I32o (%%I32o = 11145401322)"), + (tUINT32)1234567890 + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %I32x (%%I32x = 499602d2) | %I32X (%%I32X = 499602D2)"), + (tUINT32)1234567890, + (tUINT32)1234567890 + ); + + + + l_pTrace->P7_INFO(l_hModule, + TM("Decamical %I64d (%%I64d = 1234567890987) | %I64i (%%I64i = 1234567890987)"), + (tINT64)1234567890987ULL, + (tINT64)1234567890987ULL + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Octal %I64o (%%I64o = 21756176604053)"), + (tUINT64)1234567890987ULL + ); + + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %llx (%%llx = ffaabbccee12) | %llX (%%llX = FFAABBCCEE12)"), + (tUINT64)0xffaabbccee12ULL, + (tUINT64)0xFFAABBCCEE12ULL + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Bin %b (%%b = 10101010101010101) | %#b (%%#b = b10101010101010101)"), + (tUINT32)0x15555, + (tUINT32)0x15555 + ); + + + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Floating point"), 0); + + + l_pTrace->P7_INFO(l_hModule, + TM("%f (%%f 123456.7890) | %e (%%e) | %E (%%E) | %G (%%G) | %g (%%g) | %A (%%A) | %a (%%a)"), + (tDOUBLE)123456.7890, + (tDOUBLE)123456.7890, + (tDOUBLE)123456.7890, + (tDOUBLE)123456.7890, + (tDOUBLE)123456.7890, + (tDOUBLE)123456.7890, + (tDOUBLE)123456.7890 + ); + + + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Pointer"), 0); + + #if defined(GTX64) + l_pTrace->P7_DEBUG(l_hModule, + TM("%p (0xDEADBEEFCDCDCDCD), %s (Some string)"), + 0xDEADBEEFCDCDCDCDull, + TM("Some string")); + #else + l_pTrace->P7_DEBUG(l_hModule, + TM("%p (0xDEADBEEF), %s (Some string)"), + 0xDEADBEEFu, + TM("Some string")); + #endif + + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Long VA test"), 0); + + l_pTrace->P7_INFO(l_hModule, + TM("%s (String1), %.*s ([x]s is unsupported by P7) %d(1), %d(2), %d(3), %d(4) ") + TM("%I64X(ABCDEF12345678) %d(5), %d(6), %d(7), %d(8) ") + TM("%llx(abcdef12345678) %d(9), %d(10), %d(11), %d(12) ") + TM("%f(987654321.12345), %d(13), %jd(100500), %d(14), %d(15), %d(16) ") + TM("%c(X) %d(17), %d(18), %d(19), %d(20) ") + TM("%hd(32000) %d(21), %d(22), %d(23), %d(24) ") + TM("%s(String2) %d(25), %d(26), %d(27), %d(28), %.04f(123456.7890), % 5lld( 30)"), + TM("String1"), + 100, + TM("String2"), + (tINT32)1, + (tINT32)2, + (tINT32)3, + (tINT32)4, + (tUINT64)0xABCDEF12345678ULL, + (tINT32)5, + (tINT32)6, + (tINT32)7, + (tINT32)8, + (tUINT64)0xABCDEF12345678ULL, + (tINT32)9, + (tINT32)10, + (tINT32)11, + (tINT32)12, + (tDOUBLE)987654321.12345, + (tINT32)13, + (uintmax_t)100500, + (tINT32)14, + (tINT32)15, + (tINT32)16, + TM('X'), + (tINT32)17, + (tINT32)18, + (tINT32)19, + (tINT32)20, + (tINT16)32000, + (tINT32)21, + (tINT32)22, + (tINT32)23, + (tINT32)24, + TM("String2"), + (tINT32)25, + (tINT32)26, + (tINT32)27, + (tINT32)28, + (tDOUBLE)123456.789, + (tUINT64)30ull + ); + + //////////////////////////////////////////////////////////////////////////// + l_pTrace->P7_DEBUG(l_hModule, TM("Format tests"), 0); + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %#X (%%#X = 0xDEADBEEF) | {%#*X} (%%#*X = { 0xDEADBEEF}})"), + (tUINT32)0xDEADBEEF, + 12, + (tUINT32)0xDEADBEEF + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Hex %#012X (%%#012X = 0x00DEADBEEF) | {%#-*.*X} (%%#-14.10X = {0x00DEADBEEF }})"), + (tUINT32)0xDEADBEEF, + 14, + 10, + (tUINT32)0xDEADBEEF + ); + + l_pTrace->P7_INFO(l_hModule, + TM("Hex {%+10d} (%%+10d = { +1234567}) | {%+*.*d} (%%+*.*d = { +0001234567}})"), + (tUINT32)1234567, + 12, + 10, + (tUINT32)1234567 + ); + + } + if (!l_pTrace->Unregister_Thread(0)) + { + printf("Error: Unregister_Thread() failed\n"); + } + +l_lExit: + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_03 + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 4 // +//////////////////////////////////////////////////////////////////////////////// +// Here we send so much traces as we can // +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//Test_04 +int Test_04(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + tBOOL l_bExit = FALSE; + tUINT32 l_dwTime = GetTickCount(); + tUINT32 l_dwSent = 0; + tUINT32 l_dwRejected = 0; + IP7_Trace *l_pTrace = NULL; + IP7_Trace::hModule l_hModule = NULL; + const tXCHAR *l_pName = TM("Speed test"); + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test create one P7 client and one P7.Trace for sending\n"); + printf("so much traces as you hardware can and print statistics\n"); + goto l_lExit; + } + } + + l_pClient = P7_Create_Client(TM("/P7.PSize=1472 /P7.Pool=32768")); + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized. Exit\n"); + goto l_lExit; + } + + l_pTrace = P7_Create_Trace(l_pClient, l_pName); + if (NULL == l_pClient) + { + printf("Error: P7.Trace engine was not initialized. Exit\n"); + goto l_lExit; + } + + if (!l_pTrace->Register_Module(TM("Test #4"), &l_hModule)) + { + printf("Error: Register_Module() failed\n"); + } + + + if (!l_pTrace->Register_Thread(TM("Application"), 0)) + { + printf("Error: Register_Thread() failed\n"); + } + + + //////////////////////////////////////////////////////////////////////////// + while (FALSE == l_bExit) + { + for (tUINT32 l_dwI = 0; l_dwI < 10000; l_dwI ++) + { + if (l_pTrace->P7_QDEBUG(0, l_hModule, TM("Strings test %d"), l_dwI)) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + + if (CTicks::Difference(GetTickCount(), l_dwTime) >= 1000) + { + printf("Sent = %d Rejected = (%d) / %d ms\n", + l_dwSent, + l_dwRejected, + CTicks::Difference(GetTickCount(), l_dwTime) + ); + + l_dwTime = GetTickCount(); + l_dwSent = 0; + l_dwRejected = 0; + + if ( (Is_Key_Hit()) + && (27 == Get_Char()) + ) + { + printf("Esc ... exiting\n"); + l_bExit = TRUE; + } + + } + }//while (FALSE == l_bExit) + + l_pTrace->P7_INFO(l_hModule, TM("Done !"), 0); + + if (!l_pTrace->Unregister_Thread(0)) + { + printf("Error: Unregister_Thread() failed\n"); + } + +l_lExit: + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_04 + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 5 // +//////////////////////////////////////////////////////////////////////////////// +// Here we test telemetry creation and destroy and simple interface tests // +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//Test_05 + +#define TEST_05_COUNTERS_COUNT (5) + +int Test_05(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + IP7_Telemetry *l_pTelemetry = NULL; + tUINT32 l_dwCount = 1000; + tBOOL l_bError = FALSE; + tXCHAR l_pChannel[128]; + tXCHAR l_pCounter[128]; + tUINT16 l_pID[TEST_05_COUNTERS_COUNT]; + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test create and destroy P7 and telemetry in loop\n"); + printf("Command line arguments:\n"); + printf("/Count : Count iterations\n"); + printf(" Default value - 1000, min 1, max - uint32\n"); + printf(" Example: /Count=10000\n"); + goto l_lExit; + } + else if (0 == STRNICMP(i_pArgV[l_iI], TEST_01_COUNT, LENGTH(TEST_01_COUNT)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_01_COUNT) - 1, "%u", &l_dwCount); + if (1 > l_dwCount) + { + l_dwCount = 1; + } + } + } + + printf("Start: Iterations count %d\n", l_dwCount); + + for (tUINT32 l_dwI = 0; l_dwI < l_dwCount; l_dwI++) + { + printf("Iteration = %d\n", l_dwI); + + l_pClient = P7_Create_Client(NULL); + + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized. Iteration = %d, Exit\n", l_dwI); + l_bError = TRUE; + } + else + { + for (tUINT32 l_dwJ = 0; l_dwJ < 3; l_dwJ++) + { + SPRINTF(l_pChannel, TM("Telemetry[%03d - %02d]"), l_dwI, l_dwJ); + l_pTelemetry = P7_Create_Telemetry(l_pClient, l_pChannel); + + if (l_pTelemetry) + { + memset(l_pID, 0, sizeof(l_pID)); + + if (FALSE == l_bError) + { + for (tUINT32 l_dwK = 0; l_dwK < TEST_05_COUNTERS_COUNT; l_dwK++) + { + SPRINTF(l_pCounter, TM("Counter %02d"), l_dwK); + + if (FALSE == l_pTelemetry->Create(l_pCounter, + 0, + 0, + 10000, + 9000, + 1, + &l_pID[l_dwK] + ) + ) + { + printf("Error: Failed to create counter. Iteration = %d:%d:%d Exit\n", + l_dwI, + l_dwJ, + l_dwK + ); + l_bError = TRUE; + } + } + } + + + if (FALSE == l_bError) + { + for (tUINT32 l_dwK = 0; l_dwK < TEST_05_COUNTERS_COUNT; l_dwK++) + { + SPRINTF(l_pCounter, TM("Counter %02d"), l_dwK); + + if (FALSE == l_pTelemetry->Find(l_pCounter, &l_pID[l_dwK])) + { + printf("Error: Failed to find counter. Iteration = %d:%d:%d Exit\n", + l_dwI, + l_dwJ, + l_dwK + ); + l_bError = TRUE; + } + } + } + + if (FALSE == l_bError) + { + SPRINTF(l_pCounter, TM("Counter")); + + tUINT16 l_bID = 0; + if (TRUE == l_pTelemetry->Find(l_pCounter, &l_bID)) + { + printf("Error: Failed to find counter. Iteration = %d:%d Exit\n", + l_dwI, + l_dwJ + ); + l_bError = TRUE; + } + } + + if (FALSE == l_bError) + { + for (tUINT32 l_dwJ = 0; l_dwJ < 100000; l_dwJ ++) + { + l_pTelemetry->Add(l_pID[l_dwJ % TEST_05_COUNTERS_COUNT], l_dwJ); + } + } + + l_pTelemetry->Release(); + l_pTelemetry = NULL; + + CThShell::Sleep(500); + } + else + { + printf("Error: P7_Create_Telemetry failed. Iteration = %d, Exit\n", l_dwI); + l_bError = TRUE; + } + } + + l_pClient->Release(); + l_pClient = NULL; + } + + if (l_bError) + { + break; + } + } + +l_lExit: + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_05 + + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 6 // +//////////////////////////////////////////////////////////////////////////////// +// Here we send so much telemetry samples as we can // +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//Test_06 + +#define TEST_06_COUNTERS_COUNT (2) + +int Test_06(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + IP7_Telemetry *l_pTelemetry = NULL; + + tBOOL l_bError = FALSE; + tBOOL l_bExit = FALSE; + tUINT32 l_dwSent = 0; + tUINT32 l_dwRejected = 0; + tUINT32 l_dwTime = 0; + + tXCHAR l_pCounter[128]; + tUINT16 l_pID[TEST_06_COUNTERS_COUNT]; + + UNUSED_ARG(l_bError); + UNUSED_ARG(l_pCounter); + + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test send telemetry samples with max. possible speed\n"); + goto l_lExit; + } + } + + l_pClient = P7_Create_Client(TM("/P7.PSize=1472 /P7.Pool=32768")); + + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized"); + goto l_lExit; + } + + l_pTelemetry = P7_Create_Telemetry(l_pClient, TM("Tel. Speed Test")); + if (NULL == l_pTelemetry) + { + printf("Error: P7 Telemetry was not initialized"); + goto l_lExit; + } + + + memset(l_pID, 0, sizeof(l_pID)); + + for (tUINT32 l_dwK = 0; l_dwK < TEST_06_COUNTERS_COUNT; l_dwK++) + { + SPRINTF(l_pCounter, TM("Counter %02d"), l_dwK); + + if (FALSE == l_pTelemetry->Create(l_pCounter, + 0, + 0, + 10000, + 9500, + 1, + &l_pID[l_dwK] + ) + ) + { + printf("Error: Failed to create counter %d Exit\n", l_dwK); + goto l_lExit; + } + } + + //////////////////////////////////////////////////////////////////////////// + + l_dwTime = GetTickCount(); + + while (FALSE == l_bExit) + { + for (tUINT32 l_dwI = 0; l_dwI < 10000; l_dwI ++) + { + if (l_pTelemetry->Add(l_pID[l_dwI % TEST_06_COUNTERS_COUNT], l_dwI)) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + + if (CTicks::Difference(GetTickCount(), l_dwTime) >= 1000) + { + printf("Sent = %d Rejected = (%d) / %d ms\n", + l_dwSent, + l_dwRejected, + CTicks::Difference(GetTickCount(), l_dwTime) + ); + l_dwTime = GetTickCount(); + l_dwSent = 0; + l_dwRejected = 0; + + if ( (Is_Key_Hit()) + && (27 == Get_Char()) + ) + { + printf("Esc ... exiting\n"); + l_bExit = TRUE; + } + + } + }//while (FALSE == l_bExit) + + +l_lExit: + if (l_pTelemetry) + { + l_pTelemetry->Release(); + l_pTelemetry = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_06 + + + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 7 // +//////////////////////////////////////////////////////////////////////////////// +// Here we check shared memory // +//////////////////////////////////////////////////////////////////////////////// + +#define SHARED_TRACE TM("P7.Trace.Shared") +#define SHARED_TELEMETRY TM("P7.Trace.Telemetry") + +//////////////////////////////////////////////////////////////////////////////// +//Test_07 +int Test_07(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + IP7_Trace *l_pTrace = NULL; + IP7_Trace::hModule l_hModule = NULL; + IP7_Telemetry *l_pTelemetry = NULL; + tBOOL l_bExit = FALSE; + tUINT16 l_bID = 0; + tUINT32 l_dwTime = GetTickCount(); + tUINT32 l_dwIter = 0; + tBOOL l_bError = FALSE; + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test ckeck wokring of shared memory and next functions:\n" + " - IP7_Trace::Share(...)\n" + " - P7_Get_Shared_Trace\n" + " - IP7_Telemetry::Share(...)\n" + " - P7_Get_Shared_Telemetry(...)" + ); + + goto l_lExit; + } + } + + l_pClient = P7_Create_Client(TM("/P7.PSize=1472 /P7.Pool=32768")); + + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized"); + goto l_lExit; + } + + printf("Entering to working cycle, press Esc to quit\n"); + + //////////////////////////////////////////////////////////////////////////// + while (FALSE == l_bExit) + { + l_pTelemetry = P7_Create_Telemetry(l_pClient, TM("Telemetry")); + if (NULL == l_pTelemetry) + { + printf("Error: P7 Telemetry was not initialized"); + goto l_lExit; + } + + l_pTrace = P7_Create_Trace(l_pClient, TM("Trace")); + if (NULL == l_pTelemetry) + { + printf("Error: P7 trace was not initialized"); + goto l_lExit; + } + + if (!l_pTrace->Register_Thread(TM("Application"), 0)) + { + printf("Error: Register_Thread() failed\n"); + } + + if (FALSE == l_pTelemetry->Create(TM("Counter"), 0, 0, 1000, 950, 1, &l_bID)) + { + printf("Error: Failed to create counter Exit\n"); + goto l_lExit; + } + + if (FALSE == l_pTelemetry->Share(SHARED_TELEMETRY)) + { + printf("Error: Failed to share Telemetry instance, exit\n"); + goto l_lExit; + } + + if (FALSE == l_pTrace->Share(SHARED_TRACE)) + { + printf("Error: Failed to share Trace instance, exit\n"); + goto l_lExit; + } + + for (tUINT32 l_dwI = 0; l_dwI < 10; l_dwI++) + { + IP7_Trace *l_pSTtrace = P7_Get_Shared_Trace(SHARED_TRACE); + IP7_Telemetry *l_pSTelemetry = P7_Get_Shared_Telemetry(SHARED_TELEMETRY); + + if ( (l_pSTtrace) + && (l_pSTelemetry) + ) + { + if (!l_pSTtrace->Register_Module(TM("Test #7"), &l_hModule)) + { + printf("Error: Register_Module() failed\n"); + } + + for (tUINT32 l_dwJ = 0; l_dwJ < 1000; l_dwJ++) + { + l_pSTtrace->P7_TRACE(l_hModule, TM("Test:%d"), l_dwJ); + l_pSTelemetry->Add(l_bID, (tDOUBLE)l_dwJ); + } + } + else + { + l_bError = TRUE; + } + + if (l_pSTtrace) + { + l_pSTtrace->Release(); + l_pSTtrace = NULL; + } + + if (l_pSTelemetry) + { + l_pSTelemetry->Release(); + l_pSTelemetry = NULL; + } + + if (l_bError) + { + break; + } + + CThShell::Sleep(1); + }//for (tUINT32 l_dwI = 0; l_dwI < 10; l_dwI++) + + + if (CTicks::Difference(GetTickCount(), l_dwTime) >= 1000) + { + l_dwTime = GetTickCount(); + + if ( (Is_Key_Hit()) + && (27 == Get_Char()) + ) + { + printf("Esc ... exiting\n"); + l_bExit = TRUE; + } + + } + + if (l_pTelemetry) + { + l_pTelemetry->Release(); + l_pTelemetry = NULL; + } + + + if (!l_pTrace->Unregister_Thread(0)) + { + printf("Error: Unregister_Thread() failed\n"); + } + + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + if (l_bError) + { + break; + } + + printf("Iteration = %d\n", l_dwIter++); + }//while (FALSE == l_bExit) + +l_lExit: + if (l_pTelemetry) + { + l_pTelemetry->Release(); + l_pTelemetry = NULL; + } + + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_07 + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 8 // +//////////////////////////////////////////////////////////////////////////////// +// Here we create so much telemetry counters as we can // +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//Test_08 + +#define TEST_08_COUNTERS_COUNT (65534) +#define TEST_08_COUNTERS_ACTIVE_COUNT 256 //TEST_08_COUNTERS_COUNT/64 + +int Test_08(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + IP7_Telemetry *l_pTelemetry = NULL; + + tBOOL l_bError = FALSE; + tBOOL l_bExit = FALSE; + tUINT32 l_dwSent = 0; + tUINT32 l_dwRejected = 0; + tUINT32 l_dwTime = 0; + tDOUBLE l_dbVal = 0; + + tXCHAR l_pCounter[4096]; + const tXCHAR *l_pExtraText[] = {TM("You can do anything, but not everything"), + TM("Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away"), + TM("The richest man is not he who has the most, but he who needs the least"), + TM("Courage is not the absence of fear, but rather the judgement that something else is more important than fear."), + TM("When hungry, eat your rice; when tired, close your eyes. Fools may laugh at me, but wise men will know what I mean.")}; + tUINT16 l_pID[TEST_08_COUNTERS_COUNT]; + + UNUSED_ARG(l_bError); + UNUSED_ARG(l_pCounter); + + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test send telemetry samples with max. possible speed\n"); + goto l_lExit; + } + } + + l_pClient = P7_Create_Client(TM("/P7.PSize=1472 /P7.Pool=32768")); + + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized"); + goto l_lExit; + } + + l_pTelemetry = P7_Create_Telemetry(l_pClient, TM("Tel. Speed Test")); + if (NULL == l_pTelemetry) + { + printf("Error: P7 Telemetry was not initialized"); + goto l_lExit; + } + + + memset(l_pID, 0, sizeof(l_pID)); + + for (tUINT32 l_dwK = 0; l_dwK < TEST_08_COUNTERS_COUNT; l_dwK++) + { + SPRINTF(l_pCounter, TM("Test counter group #%04d/Counter Index #%04d {%s}"), + l_dwK / 256, + l_dwK, + l_pExtraText[l_dwK % LENGTH(l_pExtraText)] + ); + + if (FALSE == l_pTelemetry->Create(l_pCounter, + 0.0, + 0.0, + 10000.0, + 9500.0, + (l_dwK >= (TEST_08_COUNTERS_COUNT - TEST_08_COUNTERS_ACTIVE_COUNT)) ? TRUE : FALSE, + &l_pID[l_dwK] + ) + ) + { + printf("Error: Failed to create counter %d Exit\n", l_dwK); + goto l_lExit; + } + } + + //////////////////////////////////////////////////////////////////////////// + + l_dwTime = GetTickCount(); + + while (FALSE == l_bExit) + { + for (tUINT32 l_dwI = 0; l_dwI < TEST_08_COUNTERS_ACTIVE_COUNT; l_dwI ++) + { + l_dbVal += 0.5; + if (l_pTelemetry->Add(l_pID[TEST_08_COUNTERS_COUNT - l_dwI - 1], l_dbVal)) + { + l_dwSent ++; + } + else + { + l_dwRejected ++; + } + } + + if (l_dbVal > 10000.0) + { + l_dbVal = 0.0; + CThShell::Sleep(1); + } + + if (CTicks::Difference(GetTickCount(), l_dwTime) >= 1000) + { + printf("Sent = %d Rejected = (%d) / %d ms\n", + l_dwSent, + l_dwRejected, + CTicks::Difference(GetTickCount(), l_dwTime) + ); + l_dwTime = GetTickCount(); + l_dwSent = 0; + l_dwRejected = 0; + + if ( (Is_Key_Hit()) + && (27 == Get_Char()) + ) + { + printf("Esc ... exiting\n"); + l_bExit = TRUE; + } + + } + }//while (FALSE == l_bExit) + + +l_lExit: + if (l_pTelemetry) + { + l_pTelemetry->Release(); + l_pTelemetry = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_08 + + +//////////////////////////////////////////////////////////////////////////////// +// TEST 9 // +//////////////////////////////////////////////////////////////////////////////// +// Here we calling flush periodically // +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +//Test_09 + +int Test_09(int i_iArgC, char* i_pArgV[]) +{ + IP7_Client *l_pClient = NULL; + IP7_Telemetry *l_pTelemetry = NULL; + IP7_Trace *l_pTrace = NULL; + tUINT32 l_dwTime = 0; + + tBOOL l_bExit = FALSE; + tDOUBLE l_dbVal = 0; + tUINT16 l_pID = P7TELEMETRY_INVALID_ID_V2; + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_HELP, LENGTH(TEST_HELP)-1)) + { + printf("This test call flush peridically\n"); + goto l_lExit; + } + } + + l_pClient = P7_Create_Client(TM("/P7.PSize=1472 /P7.Pool=32768")); + + if (NULL == l_pClient) + { + printf("Error: P7 engine was not initialized"); + goto l_lExit; + } + + + l_pTrace = P7_Create_Trace(l_pClient, TM("Trace flush")); + if (NULL == l_pTrace) + { + printf("Error: P7 Trace was not initialized"); + goto l_lExit; + } + + l_pTelemetry = P7_Create_Telemetry(l_pClient, TM("Telemetry flush")); + + if (l_pTelemetry) + { + if (FALSE == l_pTelemetry->Create(TM("Test counter"), + 0.0, + 0.0, + 10000.0, + 9500.0, + TRUE, + &l_pID + ) + ) + { + printf("Error: Failed to create counter Exit\n"); + goto l_lExit; + } + } + + //////////////////////////////////////////////////////////////////////////// + + l_dwTime = GetTickCount(); + + while (FALSE == l_bExit) + { + l_dbVal += 0.5; + + if (l_pTelemetry) + { + l_pTelemetry->Add(l_pID, l_dbVal); + } + + CThShell::Sleep(10); + if (l_dbVal > 10000.0) + { + l_dbVal = 0.0; + } + + l_pTrace->P7_ERROR(NULL, TM("Test trace %f"), l_dbVal); + + if (CTicks::Difference(GetTickCount(), l_dwTime) >= 1000) + { + P7_Flush(); + l_dwTime = GetTickCount(); + + if ( (Is_Key_Hit()) + && (27 == Get_Char()) + ) + { + printf("Esc ... exiting\n"); + l_bExit = TRUE; + } + } + }//while (FALSE == l_bExit) + + +l_lExit: + if (l_pTrace) + { + l_pTrace->Release(); + l_pTrace = NULL; + } + + if (l_pTelemetry) + { + l_pTelemetry->Release(); + l_pTelemetry = NULL; + } + + if (l_pClient) + { + l_pClient->Release(); + l_pClient = NULL; + } + + return 0; +}//Test_09 + + +//////////////////////////////////////////////////////////////////////////////// +// MAIN // +//////////////////////////////////////////////////////////////////////////////// +int main(int i_iArgC, char* i_pArgV[]) +{ + printf("******************************************************************\n"); + printf("P7 Traces test tool\n"); + printf("******************************************************************\n"); + + int l_iTest = -1; + int l_iReturn = 0; + + for (int l_iI = 0; l_iI < i_iArgC; l_iI++) + { + if (0 == STRNICMP(i_pArgV[l_iI], TEST_NUMBER, LENGTH(TEST_NUMBER)-1)) + { + sscanf(i_pArgV[l_iI] + LENGTH(TEST_NUMBER)-1, "%d", &l_iTest); + } + } + + if (1 == l_iTest) + { + l_iReturn = Test_01(i_iArgC, i_pArgV); + } + else if (2 == l_iTest) + { + l_iReturn = Test_02(i_iArgC, i_pArgV); + } + else if (3 == l_iTest) + { + l_iReturn = Test_03(i_iArgC, i_pArgV); + } + else if (4 == l_iTest) + { + l_iReturn = Test_04(i_iArgC, i_pArgV); + } + else if (5 == l_iTest) + { + l_iReturn = Test_05(i_iArgC, i_pArgV); + } + else if (6 == l_iTest) + { + l_iReturn = Test_06(i_iArgC, i_pArgV); + } + else if (7 == l_iTest) + { + l_iReturn = Test_07(i_iArgC, i_pArgV); + } + else if (8 == l_iTest) + { + l_iReturn = Test_08(i_iArgC, i_pArgV); + } + else if (9 == l_iTest) + { + l_iReturn = Test_09(i_iArgC, i_pArgV); + } + else + { + printf("ERROR: Test number is not specified or out of range\n"); + printf("Test command line arguments:\n"); + printf(" /Test : test number to execute. Min value = 1, max value = 6.\n"); + printf(" Example: /Test=1\n"); + printf(" To get help about test: /Test=1 /?\n"); + printf(" /? : show help for specific test.\n"); + printf(" Example: /Test=1 /?\n"); + PRINTF(CLIENT_HELP_STRING); + } + + + + DUMP_MEMORY_LEAKS(); + + return l_iReturn; +} + + +//"${OUTPUT_PATH}" /P7.Addr=192.168.0.3 /P7.Port=9009 /P7.Verb=1 /P7.Window=128 /P7.PSize=1474 /Test=3 /Speed=10 /Count=3 /P7.Pool=4096 diff --git a/ECSAPI/vcpkg-configuration.json b/vcpkg-configuration.json similarity index 100% rename from ECSAPI/vcpkg-configuration.json rename to vcpkg-configuration.json diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..fc7170b --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,9 @@ +{ + "dependencies": [ + "entt", + "vulkan", + {"name": "sdl2", "features": ["vulkan"]}, + "rmlui", + "gtest" + ] +}