diff --git a/Core/Base/Check.cpp b/Core/Base/Check.cpp index 9da4a07..361b0bc 100644 --- a/Core/Base/Check.cpp +++ b/Core/Base/Check.cpp @@ -4,38 +4,33 @@ #include #include +bool check_port(long long port) { return port >= 0 && port <= 65535; } +bool check_ipv4(const std::string &ip) { + std::istringstream ss(ip); + std::string segment; + int count = 0; + // 检查是否为空字符串或以点号结尾 + if (ip.empty() || ip.back() == '.') { + return false; + } - -bool check_port(long long port) { - return port >= 0 && port <= 65535; -} -bool check_ipv4(const std::string& ip) { - std::istringstream ss(ip); - std::string segment; - int count = 0; - - // 检查是否为空字符串或以点号结尾 - if (ip.empty() || ip.back() == '.') { - return false; + while (std::getline(ss, segment, '.')) { + ++count; + // 检查是否为数字且在 0-255 范围内 + if (segment.empty() || segment.size() > 3 || + !std::all_of(segment.begin(), segment.end(), ::isdigit) || + std::stoi(segment) < 0 || std::stoi(segment) > 255) { + return false; } - - while (std::getline(ss, segment, '.')) { - ++count; - // 检查是否为数字且在 0-255 范围内 - if (segment.empty() || segment.size() > 3 || - !std::all_of(segment.begin(), segment.end(), ::isdigit) || - std::stoi(segment) < 0 || std::stoi(segment) > 255) { - return false; - } - // 防止前导零,例如 "01" - if (segment.size() > 1 && segment[0] == '0') { - return false; - } + // 防止前导零,例如 "01" + if (segment.size() > 1 && segment[0] == '0') { + return false; } + } - // IPv4 应该有 4 个段 - return count == 4; + // IPv4 应该有 4 个段 + return count == 4; } // bool check_ipv4(const std::string& ip) { // std::istringstream ss(ip); @@ -58,89 +53,90 @@ bool check_ipv4(const std::string& ip) { // return count == 4; // IPv4 应该有 4 个段 // } -unsigned int ip_to_int(const std::string& ip) { - unsigned int result = 0; - std::stringstream ss(ip); - std::string byte; - for (int i = 0; i < 4; ++i) { - std::getline(ss, byte, '.'); - result |= (std::stoi(byte) << (24 - i * 8)); - } - return result; +unsigned int ip_to_int(const std::string &ip) { + unsigned int result = 0; + std::stringstream ss(ip); + std::string byte; + for (int i = 0; i < 4; ++i) { + std::getline(ss, byte, '.'); + result |= (std::stoi(byte) << (24 - i * 8)); + } + return result; } // 判断 IP 地址是否在子网内 -bool is_in_subnet(const std::string& ip, const std::string& netmask, const std::string& gateway) { - unsigned int ipInt = ip_to_int(ip); - unsigned int netmaskInt = ip_to_int(netmask); - unsigned int gatewayInt = ip_to_int(gateway); +bool is_in_subnet(const std::string &ip, const std::string &netmask, + const std::string &gateway) { + unsigned int ipInt = ip_to_int(ip); + unsigned int netmaskInt = ip_to_int(netmask); + unsigned int gatewayInt = ip_to_int(gateway); - // 计算网络地址 - unsigned int networkAddress = ipInt & netmaskInt; - return (networkAddress == (gatewayInt & netmaskInt)); + // 计算网络地址 + unsigned int networkAddress = ipInt & netmaskInt; + return (networkAddress == (gatewayInt & netmaskInt)); } // check 函数,验证 IP、子网掩码和网关 -bool check_ip_netmask_gateway(const std::string& ip, const std::string& netmask, const std::string& gateway) { - // 验证 IP 地址、子网掩码和网关是否合法 - if (!check_ipv4(ip)) { - std::cerr << "Invalid IP address: " << ip << std::endl; - return false; - } - if (!check_ipv4(netmask)) { - std::cerr << "Invalid netmask: " << netmask << std::endl; - return false; - } - if (!check_ipv4(gateway)) { - std::cerr << "Invalid gateway: " << gateway << std::endl; - return false; - } +bool check_ip_netmask_gateway(const std::string &ip, const std::string &netmask, + const std::string &gateway) { + // 验证 IP 地址、子网掩码和网关是否合法 + if (!check_ipv4(ip)) { + std::cerr << "Invalid IP address: " << ip << std::endl; + return false; + } + if (!check_ipv4(netmask)) { + std::cerr << "Invalid netmask: " << netmask << std::endl; + return false; + } + if (!check_ipv4(gateway)) { + std::cerr << "Invalid gateway: " << gateway << std::endl; + return false; + } - // 验证网关是否在同一个子网内 - if (!is_in_subnet(ip, netmask, gateway)) { - std::cerr << "Gateway is not in the same subnet as IP address." << std::endl; - return false; - } + // 验证网关是否在同一个子网内 + if (!is_in_subnet(ip, netmask, gateway)) { + std::cerr << "Gateway is not in the same subnet as IP address." + << std::endl; + return false; + } - return true; + return true; } - - #ifdef _USE_GTEST #include // 测试 IPv4 地址的有效性 TEST(CheckIPv4Test, ValidIPv4Addresses) { - // 合法 IPv4 测试用例 - std::vector validIPs = { - "192.168.0.1", // 合法 - "255.255.255.255", // 合法 - "0.0.0.0", // 合法 - "127.0.0.1" // 合法 - }; + // 合法 IPv4 测试用例 + std::vector validIPs = { + "192.168.0.1", // 合法 + "255.255.255.255", // 合法 + "0.0.0.0", // 合法 + "127.0.0.1" // 合法 + }; - for (const auto& ip : validIPs) { - EXPECT_TRUE(check_ipv4(ip)) << "Failed for valid IP: " << ip; - } + for (const auto &ip : validIPs) { + EXPECT_TRUE(check_ipv4(ip)) << "Failed for valid IP: " << ip; + } } TEST(CheckIPv4Test, InvalidIPv4Addresses) { - // 不合法的 IPv4 测试用例 - std::vector invalidIPs = { - "192.168.1", // 不合法,段数不足 - "256.256.256.256", // 不合法,数值超出范围 - "192.168.01.1", // 不合法,前导零 - "192.168..1", // 不合法,空段 - "abc.def.ghi.jkl", // 不合法,非数字 - "192.168.1.1.", // 不合法,多余的点 - ".192.168.1.1", // 不合法,多余的点 - "192.168.1.1.1", // 不合法,段数超出 - "127.0.0.1112" // 不合法,段数超出 - }; + // 不合法的 IPv4 测试用例 + std::vector invalidIPs = { + "192.168.1", // 不合法,段数不足 + "256.256.256.256", // 不合法,数值超出范围 + "192.168.01.1", // 不合法,前导零 + "192.168..1", // 不合法,空段 + "abc.def.ghi.jkl", // 不合法,非数字 + "192.168.1.1.", // 不合法,多余的点 + ".192.168.1.1", // 不合法,多余的点 + "192.168.1.1.1", // 不合法,段数超出 + "127.0.0.1112" // 不合法,段数超出 + }; - for (const auto& ip : invalidIPs) { - EXPECT_FALSE(check_ipv4(ip)) << "Failed for invalid IP: " << ip; - } + for (const auto &ip : invalidIPs) { + EXPECT_FALSE(check_ipv4(ip)) << "Failed for invalid IP: " << ip; + } } // TEST(Check, ipv4) { @@ -170,6 +166,4 @@ TEST(CheckIPv4Test, InvalidIPv4Addresses) { // } // } - - #endif \ No newline at end of file diff --git a/Core/Base/Check.h b/Core/Base/Check.h index fa30852..640067d 100644 --- a/Core/Base/Check.h +++ b/Core/Base/Check.h @@ -2,6 +2,7 @@ #include -bool check_ipv4(const std::string& ip); +bool check_ipv4(const std::string &ip); bool check_port(long long port); -bool check_ip_netmask_gateway(const std::string& ip, const std::string& netmask, const std::string& gateway); \ No newline at end of file +bool check_ip_netmask_gateway(const std::string &ip, const std::string &netmask, + const std::string &gateway); \ No newline at end of file diff --git a/Core/Base/Coro_Result.h b/Core/Base/Coro_Result.h index 8b02b1d..4ae803d 100644 --- a/Core/Base/Coro_Result.h +++ b/Core/Base/Coro_Result.h @@ -6,52 +6,41 @@ #include namespace Psc::coro { -template -class Result_Completion { +template class Result_Completion { public: - explicit Result_Completion(std::shared_ptr> promise) - : promise_(std::move(promise)) - { - } - void operator()(T value) - { - promise_->set_result(std::move(value)); - } - void set_exception(std::exception_ptr exception) - { - promise_->set_exception(exception); - } + explicit Result_Completion( + std::shared_ptr> promise) + : promise_(std::move(promise)) {} + void operator()(T value) { promise_->set_result(std::move(value)); } + void set_exception(std::exception_ptr exception) { + promise_->set_exception(exception); + } + private: - std::shared_ptr> promise_; + std::shared_ptr> promise_; }; -template <> -class Result_Completion { +template <> class Result_Completion { public: - explicit Result_Completion(std::shared_ptr> promise) - : promise_(std::move(promise)) - { - } - void operator()() - { - promise_->set_result(); - } - void set_exception(std::exception_ptr exception) - { - promise_->set_exception(exception); - } + explicit Result_Completion( + std::shared_ptr> promise) + : promise_(std::move(promise)) {} + void operator()() { promise_->set_result(); } + void set_exception(std::exception_ptr exception) { + promise_->set_exception(exception); + } + private: - std::shared_ptr> promise_; + std::shared_ptr> promise_; }; template -[[nodiscard]] concurrencpp::result callback_result(Starter&& starter) -{ - auto promise = std::make_shared>(); - auto result = promise->get_result(); - try { - std::forward(starter)(Result_Completion{promise}); - } catch (...) { - promise->set_exception(std::current_exception()); - } - return result; -} +[[nodiscard]] concurrencpp::result callback_result(Starter &&starter) { + auto promise = std::make_shared>(); + auto result = promise->get_result(); + try { + std::forward(starter)(Result_Completion{promise}); + } catch (...) { + promise->set_exception(std::current_exception()); + } + return result; } +} // namespace Psc::coro diff --git a/Core/Base/File_Helper.cpp b/Core/Base/File_Helper.cpp index a5d4357..5ff17b9 100644 --- a/Core/Base/File_Helper.cpp +++ b/Core/Base/File_Helper.cpp @@ -19,7 +19,8 @@ void File_Gather_Simple::init(const std::string &path, size_t size) { buffer.reserve(buffer_size); } -File_Gather_Simple::File_Gather_Simple(const std::string &path, size_t buffer_size) { +File_Gather_Simple::File_Gather_Simple(const std::string &path, + size_t buffer_size) { init(path, buffer_size); } void File_Gather_Simple::append(const std::uint8_t *data, size_t size) { @@ -33,7 +34,6 @@ void File_Gather_Simple::append(const std::uint8_t *data, size_t size) { flush(); } - buffer.append(reinterpret_cast(data), size); } @@ -83,7 +83,6 @@ void File_Player::rewind() { ifs.seekg(0, std::ios::beg); } - std::uint64_t File_Player::total_size() const { return total_size_; } std::uint64_t File_Player::current_offset() { @@ -113,15 +112,12 @@ double File_Player::progress() { static_cast(total_size_); } -File_Gather::File_Gather( - const std::string &path, size_t buffer_size) +File_Gather::File_Gather(const std::string &path, size_t buffer_size) : gather_file(path, buffer_size) {} -void File_Gather::init(const std::string &path, - size_t buffer_size) { +void File_Gather::init(const std::string &path, size_t buffer_size) { gather_file.init(path, buffer_size); } -void File_Gather::append(const std::uint8_t *data, - size_t size) { +void File_Gather::append(const std::uint8_t *data, size_t size) { append_speed.update(size); append_value.update(static_cast(size)); gather_file.append(data, size); diff --git a/Core/Base/JSON.cpp b/Core/Base/JSON.cpp index eb5f18a..283ddda 100644 --- a/Core/Base/JSON.cpp +++ b/Core/Base/JSON.cpp @@ -3,517 +3,561 @@ #include #include #include -#define HANDLE_ERROR(reason) JSON::handle_error(__func__, reason, __FILE__, __LINE__); +#define HANDLE_ERROR(reason) \ + JSON::handle_error(__func__, reason, __FILE__, __LINE__); namespace Psc { - std::function JSON::handle_error = [](const char* function_name, const std::string& reason, const char* file, int line) { - std::ostringstream oss; - oss << "JSON::" << function_name << " 原因:" << reason << std::endl; - oss << "位置:" << file << ":" << line << std::endl; - std::cout << oss.str(); - Psc::fail_fast(); +std::function + JSON::handle_error = [](const char *function_name, + const std::string &reason, const char *file, + int line) { + std::ostringstream oss; + oss << "JSON::" << function_name << " 原因:" << reason << std::endl; + oss << "位置:" << file << ":" << line << std::endl; + std::cout << oss.str(); + Psc::fail_fast(); }; +void skip_whitespace(std::string &s, size_t &i); +bool parse_string(std::string &s, size_t &i, std::string &out, + std::error_code &ec) noexcept; +bool parse_number(std::string &s, size_t &i, std::string &out, + std::error_code &ec) noexcept; +bool parse_object(std::string &s, size_t &i, JSON &out, + std::error_code &ec) noexcept; +bool parse_array(std::string &s, size_t &i, JSON &out, + std::error_code &ec) noexcept; - void skip_whitespace(std::string& s, size_t& i); - bool parse_string(std::string& s, size_t& i, std::string& out, std::error_code& ec) noexcept; - bool parse_number(std::string& s, size_t& i, std::string& out, std::error_code& ec) noexcept; - bool parse_object(std::string& s, size_t& i, JSON& out, std::error_code& ec) noexcept; - bool parse_array(std::string& s, size_t& i, JSON& out, std::error_code& ec) noexcept; +std::ostream &operator<<(std::ostream &os, const JSON &obj) { + os << const_cast(obj).to_json_string(); + return os; +} - std::ostream& operator<<(std::ostream& os, const JSON& obj) { - os << const_cast(obj).to_json_string(); - return os; - } +JSON::operator std::string() const { + return const_cast(this)->to_json_string(); +} - JSON::operator std::string() const { - return const_cast(this)->to_json_string(); - } +PSC_DEFINE_TRIPLE_API_CONST_METHOD_FROM_BOOL(std::string, JSON, get_string, + PSC_JSON_KEY_PARAMS) - PSC_DEFINE_TRIPLE_API_CONST_METHOD_FROM_BOOL(std::string, JSON, get_string, PSC_JSON_KEY_PARAMS) +bool JSON::get_string_ec(const std::string &key, std::string &out, + std::error_code &ec) const noexcept { + const JSON *that = get(key); + if (!that) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + out = that->val; + return true; +} - bool JSON::get_string_ec(const std::string& key, std::string& out, std::error_code& ec) const noexcept { - const JSON* that = get(key); - if (!that) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - out = that->val; - return true; - } +PSC_DEFINE_TRIPLE_API_CONST_METHOD_FROM_BOOL_0(bool, JSON, bool_val) - PSC_DEFINE_TRIPLE_API_CONST_METHOD_FROM_BOOL_0(bool, JSON, bool_val) +bool JSON::bool_val_ec(bool &out, std::error_code &ec) const noexcept { + if (val != "true" && val != "false") { + // HANDLE_ERROR(key + " Invalid bool argument: " + val) + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + out = (val == "true"); + return true; +} - bool JSON::bool_val_ec(bool& out, std::error_code& ec) const noexcept { - if (val != "true" && val != "false") { - //HANDLE_ERROR(key + " Invalid bool argument: " + val) - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - out = (val == "true"); - return true; - } +PSC_DEFINE_TRIPLE_API_CONST_METHOD_FROM_BOOL(bool, JSON, get_bool, + PSC_JSON_KEY_PARAMS) - PSC_DEFINE_TRIPLE_API_CONST_METHOD_FROM_BOOL(bool, JSON, get_bool, PSC_JSON_KEY_PARAMS) +bool JSON::get_bool_ec(const std::string &key, bool &out, + std::error_code &ec) const noexcept { + const Psc::JSON *that = get(key); + if (!that) { + // std::cout << "get" "bool" " error json not found! key:" << _key << + // " json: " << to_json_string() << std::endl; + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + return that->bool_val_ec(out, ec); +} - bool JSON::get_bool_ec(const std::string& key, bool& out, std::error_code& ec) const noexcept { - const Psc::JSON *that = get(key); - if (!that) { - // std::cout << "get" "bool" " error json not found! key:" << _key << - // " json: " << to_json_string() << std::endl; - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - return that->bool_val_ec(out, ec); - } +// JSON::JSON(std::string key, const char* val) : key(std::move(key)), +// val(std::string(val)), valueType(String) { +// } +// +// JSON::JSON(std::string key, std::string val) : key(std::move(key)), +// val(std::move(val)), valueType(String) { +// } +// +// JSON::JSON(std::string key, bool val) : key(std::move(key)), val(val ? "true" +// : "false"), valueType(Bool) { +// } +// +JSON::JSON(std::string key, const JSON &children) + : key(std::move(key)), val(children.val), valueType(children.valueType), + children(children.children) {} - // JSON::JSON(std::string key, const char* val) : key(std::move(key)), - // val(std::string(val)), valueType(String) { - // } - // - // JSON::JSON(std::string key, std::string val) : key(std::move(key)), val(std::move(val)), valueType(String) { - // } - // - // JSON::JSON(std::string key, bool val) : key(std::move(key)), val(val ? "true" : "false"), valueType(Bool) { - // } - // - JSON::JSON(std::string key, const JSON& children) : - key(std::move(key)), val(children.val), valueType(children.valueType), children(children.children) {} - - - void JSON::append_list(const std::vector& arr) { +void JSON::append_list(const std::vector &arr) { #ifdef _DEBUG - if(valueType != JsonType::Object && valueType != JsonType::Array){ - HANDLE_ERROR("append_list error! key:" + key + " not array or object " + to_json_string()) - } + if (valueType != JsonType::Object && valueType != JsonType::Array) { + HANDLE_ERROR("append_list error! key:" + key + " not array or object " + + to_json_string()) + } #else #endif - for (const JSON& j : arr) { - children.push_back(j); - } - } + for (const JSON &j : arr) { + children.push_back(j); + } +} - void JSON::append(const JSON& json) { +void JSON::append(const JSON &json) { #ifdef _DEBUG - if (valueType != JsonType::Object && valueType != JsonType::Array) - { - HANDLE_ERROR("append_list error! key:" + key + " not array or object " + to_json_string()) - } + if (valueType != JsonType::Object && valueType != JsonType::Array) { + HANDLE_ERROR("append_list error! key:" + key + " not array or object " + + to_json_string()) + } #else #endif - children.push_back(json); - } - void JSON::prepend(const JSON& json) { + children.push_back(json); +} +void JSON::prepend(const JSON &json) { #ifdef _DEBUG - if (valueType != JsonType::Object && valueType != JsonType::Array) - { - HANDLE_ERROR("append_list error! key:" + key + " not array or object " + to_json_string()) - } + if (valueType != JsonType::Object && valueType != JsonType::Array) { + HANDLE_ERROR("append_list error! key:" + key + " not array or object " + + to_json_string()) + } #else #endif - children.insert(children.begin(), json); + children.insert(children.begin(), json); +} + +bool JSON::has(const std::string &_key) const { + for (const JSON &child : children) { + if (child.key == _key) { + return true; + } + } + return false; +} +const JSON *JSON::get(const std::string &_key) const { + for (const JSON &child : children) { + if (child.key == _key) { + return &child; + } + } + // HANDLE_ERROR(_key + " not found!" + to_json_string()) + return nullptr; +} + +JSON JSON::array(const std::vector &children) { + return array("", children); +} + +JSON JSON::object(const std::vector &children) { + return object("", children); +} + +JSON JSON::array(std::string key, const std::vector &children) { + JSON ret; + ret.key = std::move(key); + ret.valueType = Array; + ret.children = children; + return ret; +} + +JSON JSON::object(std::string key, const std::vector &children) { + JSON ret; + ret.key = std::move(key); + ret.valueType = Object; + ret.children = children; + return ret; +} + +std::string JSON::get_indent(const int &indent, const std::string &indentStr) { + std::string ret; + for (int i = 0; i < indent; ++i) { + ret.append(indentStr); + } + return ret; +} + +void JSON::append_value_string(std::string &ret, const int &indent, bool isEnd, + const std::string &object_split, + const std::string &array_split, + const std::string &indentStr, + JsonType fatherType) const { + ret.append(get_indent(indent, indentStr)); + if (fatherType == Object) + ret.append("\"" + key + "\"" + ": "); + const std::string split = fatherType == Array ? array_split : object_split; + if (valueType == String) { + ret.append("\"" + val + "\""); + goto end; + } + if (valueType == Null) { + ret.append("null"); + goto end; + } + if (valueType == Number || valueType == Bool) { + ret.append(val); + goto end; + } + if (valueType == Object) { + ret.append("{" + object_split); + size_t n = children.size(); + if (n) { + for (size_t i = 0; i < n - 1; ++i) { + children[i].append_value_string(ret, indent + 2, false, object_split, + array_split, indentStr, Object); + } + children[n - 1].append_value_string(ret, indent + 2, true, object_split, + array_split, indentStr, Object); + } + ret.append(get_indent(indent, indentStr) + "}"); + goto end; + } + if (valueType == Array) { + ret.append("[" + array_split); + size_t n = children.size(); + if (n) { + for (size_t i = 0; i < n - 1; ++i) { + children[i].append_value_string(ret, indent + 1, false, object_split, + array_split, indentStr, Array); + } + children[n - 1].append_value_string(ret, indent + 1, true, object_split, + array_split, indentStr, Array); + } + ret.append(get_indent(indent, indentStr) + "]"); + goto end; + } +end: + if (!isEnd) + ret.append(","); + ret.append(split); +} + +void handleBlank(std::string &s) { + int n = static_cast(s.length()); + bool isInStr = false; + for (int i = n - 1; i >= 0; --i) { + const char &c = s[i]; + if (c == '\"') + isInStr = !isInStr; + if (isInStr) + continue; + if (c == '\n' || c == '\t' || c == ' ') { + s.erase(i, 1); + } + } +} + +std::string JSON::to_json_string(const std::string &object_split, + const std::string &array_split, + const std::string &indentStr, + const int &indent) const { + if (valueType == Bool) + return val; + if (valueType == String) + return '\"' + val + '\"'; + if (valueType == Number) + return val; + if (valueType == Null) { + if (children.size() != 0) { + HANDLE_ERROR("null 带有children 转成了字符串 (" + key + "," + val + ")" + + to_json_string()) + } + return "null"; + } + std::string ret; + // ret.append(split); + append_value_string(ret, indent, true, object_split, array_split, indentStr, + Null); + return ret; +} + +JSON::JSON() = default; + +void copy(JSON &dest, const JSON &src) { + dest.key = src.key; + dest.valueType = src.valueType; + dest.val = src.val; + auto len = src.children.size(); + dest.children.resize(len); + for (size_t i = 0; i < len; ++i) { + dest.children[i] = src.children[i]; + } +} + +JSON::JSON(const JSON &other) { copy(*this, other); } +JSON::JSON(JSON &&other) noexcept { + key = std::move(other.key); + valueType = std::move(other.valueType); + children = std::move(other.children); + val = std::move(other.val); +} + +JSON &JSON::operator=(const JSON &other) { + if (this != &other) { // 防止自赋值 + copy(*this, other); // 调用拷贝函数 + } + return *this; +} + +JSON &JSON::operator=(JSON &&other) noexcept { + if (this != &other) { + key = std::move(other.key); + valueType = other.valueType; + children = std::move(other.children); + val = std::move(other.val); + } + return *this; +} +// 解析的分割线---------------------------- + +// 如果未找到非空白字符,将 i 更新为 std::string::npos +void skip_whitespace(std::string &s, size_t &i) { + i = s.find_first_not_of(" \t\n\r\f\v", i); +} + +// 传入的 i 是 "所在的index +bool parse_string(std::string &s, size_t &i, std::string &out, + std::error_code &ec) noexcept { + ec.clear(); + i++; // skip '"' + if (s[i] == '"') { + i++; + out.clear(); + return true; + } + std::string ret; + while (true) { + if (s[i] == '"' && s[i - 1] != '\\') { + break; + } + ret += s[i]; + i++; + } + i++; + out = std::move(ret); + return true; +} + +bool parse_number(std::string &s, size_t &i, std::string &out, + std::error_code &ec) noexcept { + ec.clear(); + std::string num; + while (isdigit(s[i])) { + num += s[i++]; + } + if (s[i] == '.') { + i++; + num += '.'; + while (isdigit(s[i])) { + num += s[i++]; + } + } + out = std::move(num); + return true; +} + +bool parse_json_EX(std::string &s, size_t &i, JSON &out, + std::error_code &ec) noexcept; +PSC_DEFINE_TRIPLE_API_FROM_BOOL(JSON, parse_json, PSC_JSON_PARSE_PARAMS) + +bool parse_json_ec(const std::string &text, JSON &out, + std::error_code &ec) noexcept { + auto &t = const_cast(text); + size_t i = 0; + return parse_json_EX(t, i, out, ec); +} + +bool parse_json_EX(std::string &s, size_t &i, JSON &out, + std::error_code &ec) noexcept { + skip_whitespace(s, i); + switch (s[i]) { + case 'n': + i += 4; + out = JSON(nullptr); + return true; + case 't': + i += 4; + out = JSON(true); + return true; + case 'f': + i += 5; + out = JSON(false); + return true; + case '{': + return parse_object(s, i, out, ec); + case '[': + return parse_array(s, i, out, ec); + case '"': { + std::string str; + if (!parse_string(s, i, str, ec)) + return false; + out = JSON(std::move(str)); + return true; + } + case '-': { + i++; // skip - + JSON ret(nullptr); + ret.valueType = Number; + std::string num; + if (!parse_number(s, i, num, ec)) + return false; + ret.val = '-' + num; + out = std::move(ret); + return true; + } + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + JSON ret(nullptr); + ret.valueType = Number; + std::string num; + if (!parse_number(s, i, num, ec)) + return false; + ret.val = std::move(num); + out = std::move(ret); + return true; + } + default: { + // HANDLE_ERROR("json 解析错误! " + s + "\n") + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + } +} + +bool parse_object(std::string &s, size_t &i, JSON &out, + std::error_code &ec) noexcept { + i++; // skip '{' + skip_whitespace(s, i); + JSON ret = JSON::object(); + if (s[i] == '}') { + i++; + out = std::move(ret); + return true; + } + while (true) { + skip_whitespace(s, i); + std::string key; + if (!parse_string(s, i, key, ec)) + return false; + skip_whitespace(s, i); + if (s[i] != ':') { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + i++; + skip_whitespace(s, i); + JSON kv; + if (!parse_json_EX(s, i, kv, ec)) + return false; + skip_whitespace(s, i); + kv.key = key; + ret.children.push_back(std::move(kv)); + if (s[i] == '}') { + i++; + break; + } + if (s[i] == ',') { + i++; + } + } + out = std::move(ret); + return true; +} + +bool parse_array(std::string &s, size_t &i, JSON &out, + std::error_code &ec) noexcept { + i++; // skip '[' + skip_whitespace(s, i); + JSON ret = JSON::array(); + if (s[i] == ']') { + i++; + out = std::move(ret); + return true; + } + while (true) { + skip_whitespace(s, i); + // parseJson(s, i) + JSON kv; + if (!parse_json_EX(s, i, kv, ec)) + return false; + ret.children.push_back(std::move(kv)); + skip_whitespace(s, i); + if (s[i] == ']') { + i++; + break; + } + if (s[i] == ',') { + i++; + } + } + out = std::move(ret); + return true; +} + +PSC_DEFINE_TRIPLE_API_FROM_BOOL(JSON, parse_json_file, PSC_JSON_FILE_PARAMS) + +bool parse_json_file_ec(const std::string &file_name, JSON &out, + std::error_code &ec) noexcept { + auto readFile = [](const std::string &path, std::string &content, + std::error_code &ec) noexcept { + std::ifstream infile(path, std::ios::binary | std::ios::ate); + if (!infile.is_open()) { + ec = std::make_error_code(std::errc::no_such_file_or_directory); + return false; } - bool JSON::has(const std::string &_key) const { - for (const JSON& child : children) { - if (child.key == _key) { - return true; - } - } - return false; - } - const JSON* JSON::get(const std::string& _key) const { - for (const JSON& child : children) { - if (child.key == _key) { - return &child; - } - } - // HANDLE_ERROR(_key + " not found!" + to_json_string()) - return nullptr; + std::streamsize fileSize = infile.tellg(); + if (fileSize < 0) { + ec = std::make_error_code(std::errc::io_error); + return false; } - JSON JSON::array(const std::vector& children) { - return array("", children); + infile.seekg(0, std::ios::beg); + content.resize(static_cast(fileSize)); + if (!infile.read(content.data(), fileSize)) { + ec = std::make_error_code(std::errc::io_error); + return false; } - JSON JSON::object(const std::vector& children) { - return object("", children); + return true; + }; + + std::string text; + if (!readFile(file_name, text, ec)) + return false; + return parse_json_ec(text, out, ec); +} + +void check_json_assign_field(bool ok, const std::error_code &ec, + const Psc::JSON *that_json, const char *name) { + if (!ok) { + std::ostringstream oss; + oss << "json assign error:[" << name << "," + << Psc::platform_2_utf8(ec.message()) << "]"; + if (that_json != nullptr) { + oss << " from" << that_json->to_json_string(); } - - JSON JSON::array(std::string key, const std::vector& children) { - JSON ret; - ret.key = std::move(key); - ret.valueType = Array; - ret.children = children; - return ret; - } - - JSON JSON::object(std::string key, const std::vector& children) { - JSON ret; - ret.key = std::move(key); - ret.valueType = Object; - ret.children = children; - return ret; - } - - std::string JSON::get_indent(const int& indent, const std::string& indentStr) { - std::string ret; - for (int i = 0; i < indent; ++i) { - ret.append(indentStr); - } - return ret; - } - - void JSON::append_value_string(std::string& ret, const int& indent, bool isEnd, const std::string& object_split, - const std::string& array_split, const std::string& indentStr, JsonType fatherType) const { - ret.append(get_indent(indent, indentStr)); - if (fatherType == Object) ret.append("\"" + key + "\"" + ": "); - const std::string split = fatherType == Array ? array_split : object_split; - if (valueType == String) { - ret.append("\"" + val + "\""); - goto end; - } - if (valueType == Null) { - ret.append("null"); - goto end; - } - if (valueType == Number || valueType == Bool) { - ret.append(val); - goto end; - } - if (valueType == Object) { - ret.append("{" + object_split); - size_t n = children.size(); - if (n) { - for (size_t i = 0; i < n - 1; ++i) { - children[i].append_value_string(ret, indent + 2, false, object_split, array_split, indentStr, Object); - } - children[n - 1].append_value_string(ret, indent + 2, true, object_split, array_split, indentStr, Object); - } - ret.append(get_indent(indent, indentStr) + "}"); - goto end; - } - if (valueType == Array) { - ret.append("[" + array_split); - size_t n = children.size(); - if (n) { - for (size_t i = 0; i < n - 1; ++i) { - children[i].append_value_string(ret, indent + 1, false, object_split, array_split, indentStr, Array); - } - children[n - 1].append_value_string(ret, indent + 1, true, object_split, array_split, indentStr, Array); - } - ret.append(get_indent(indent, indentStr) + "]"); - goto end; - } - end: if (!isEnd) ret.append(","); - ret.append(split); - } - - - void handleBlank(std::string& s) { - int n = static_cast(s.length()); - bool isInStr = false; - for (int i = n - 1; i >= 0; --i) { - const char& c = s[i]; - if (c == '\"') isInStr = !isInStr; - if (isInStr) continue; - if (c == '\n' || c == '\t' || c == ' ') { - s.erase(i, 1); - } - } - } - - std::string JSON::to_json_string(const std::string& object_split, const std::string& array_split, - const std::string& indentStr, const int& indent) const { - if (valueType == Bool) return val; - if (valueType == String) return '\"' + val + '\"'; - if (valueType == Number) return val; - if (valueType == Null) { - if (children.size() != 0) { - HANDLE_ERROR( "null 带有children 转成了字符串 (" + key + "," + val + ")" + to_json_string()) - } - return "null"; - } - std::string ret; - //ret.append(split); - append_value_string(ret, indent, true, object_split, array_split, indentStr, Null); - return ret; - } - - - JSON::JSON() = default; - - void copy(JSON& dest, const JSON& src) { - dest.key = src.key; - dest.valueType = src.valueType; - dest.val = src.val; - auto len = src.children.size(); - dest.children.resize(len); - for (size_t i = 0; i < len; ++i) { - dest.children[i] = src.children[i]; - } - } - - JSON::JSON(const JSON &other) { - copy(*this, other); - } - JSON::JSON(JSON &&other) noexcept { - key = std::move(other.key); - valueType = std::move(other.valueType); - children = std::move(other.children); - val = std::move(other.val); - } - - JSON &JSON::operator=(const JSON &other) { - if (this != &other) { // 防止自赋值 - copy(*this, other); // 调用拷贝函数 - } - return *this; - } - - JSON &JSON::operator=(JSON &&other) noexcept { - if (this != &other) { - key = std::move(other.key); - valueType = other.valueType; - children = std::move(other.children); - val = std::move(other.val); - } - return *this; - } - // 解析的分割线---------------------------- - - - // 如果未找到非空白字符,将 i 更新为 std::string::npos - void skip_whitespace(std::string& s, size_t& i) { - i = s.find_first_not_of(" \t\n\r\f\v", i); - } - - // 传入的 i 是 "所在的index - bool parse_string(std::string& s, size_t& i, std::string& out, std::error_code& ec) noexcept { - ec.clear(); - i++; //skip '"' - if (s[i] == '"') { - i++; - out.clear(); - return true; - } - std::string ret; - while (true) { - if (s[i] == '"' && s[i - 1] != '\\') { - break; - } - ret += s[i]; - i++; - } - i++; - out = std::move(ret); - return true; - } - - bool parse_number(std::string& s, size_t& i, std::string& out, std::error_code& ec) noexcept { - ec.clear(); - std::string num; - while (isdigit(s[i])) { - num += s[i++]; - } - if (s[i] == '.') { - i++; - num += '.'; - while (isdigit(s[i])) { - num += s[i++]; - } - } - out = std::move(num); - return true; - } - - - - - - - bool parse_json_EX(std::string& s, size_t& i, JSON& out, std::error_code& ec) noexcept; - PSC_DEFINE_TRIPLE_API_FROM_BOOL(JSON, parse_json, PSC_JSON_PARSE_PARAMS) - - bool parse_json_ec(const std::string& text, JSON& out, std::error_code& ec) noexcept { - auto& t = const_cast(text); - size_t i = 0; - return parse_json_EX(t, i, out, ec); - } - - bool parse_json_EX(std::string& s, size_t& i, JSON& out, std::error_code& ec) noexcept { - skip_whitespace(s, i); - switch (s[i]) { - case 'n': i += 4; - out = JSON(nullptr); - return true; - case 't': i += 4; - out = JSON(true); - return true; - case 'f': i += 5; - out = JSON(false); - return true; - case '{': return parse_object(s, i, out, ec); - case '[': return parse_array(s, i, out, ec); - case '"': { - std::string str; - if (!parse_string(s, i, str, ec)) return false; - out = JSON(std::move(str)); - return true; - } - case '-': { - i++; //skip - - JSON ret(nullptr); - ret.valueType = Number; - std::string num; - if (!parse_number(s, i, num, ec)) return false; - ret.val = '-' + num; - out = std::move(ret); - return true; - } - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - JSON ret(nullptr); - ret.valueType = Number; - std::string num; - if (!parse_number(s, i, num, ec)) return false; - ret.val = std::move(num); - out = std::move(ret); - return true; - } - default: { - // HANDLE_ERROR("json 解析错误! " + s + "\n") - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - } - } - - bool parse_object(std::string& s, size_t& i, JSON& out, std::error_code& ec) noexcept { - i++; // skip '{' - skip_whitespace(s, i); - JSON ret = JSON::object(); - if (s[i] == '}') { - i++; - out = std::move(ret); - return true; - } - while (true) { - skip_whitespace(s, i); - std::string key; - if (!parse_string(s, i, key, ec)) return false; - skip_whitespace(s, i); - if (s[i] != ':') { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - i++; - skip_whitespace(s, i); - JSON kv; - if (!parse_json_EX(s, i, kv, ec)) return false; - skip_whitespace(s, i); - kv.key = key; - ret.children.push_back(std::move(kv)); - if (s[i] == '}') { - i++; - break; - } - if (s[i] == ',') { - i++; - } - } - out = std::move(ret); - return true; - } - - bool parse_array(std::string& s, size_t& i, JSON& out, std::error_code& ec) noexcept { - i++; // skip '[' - skip_whitespace(s, i); - JSON ret = JSON::array(); - if (s[i] == ']') { - i++; - out = std::move(ret); - return true; - } - while (true) { - skip_whitespace(s, i); - // parseJson(s, i) - JSON kv; - if (!parse_json_EX(s, i, kv, ec)) return false; - ret.children.push_back(std::move(kv)); - skip_whitespace(s, i); - if (s[i] == ']') { - i++; - break; - } - if (s[i] == ',') { - i++; - } - } - out = std::move(ret); - return true; - } - - - PSC_DEFINE_TRIPLE_API_FROM_BOOL(JSON, parse_json_file, PSC_JSON_FILE_PARAMS) - - bool parse_json_file_ec(const std::string& file_name, JSON& out, std::error_code& ec) noexcept { - auto readFile = [](const std::string& path, std::string& content, std::error_code& ec) noexcept { - std::ifstream infile(path, std::ios::binary | std::ios::ate); - if (!infile.is_open()) { - ec = std::make_error_code(std::errc::no_such_file_or_directory); - return false; - } - - std::streamsize fileSize = infile.tellg(); - if (fileSize < 0) { - ec = std::make_error_code(std::errc::io_error); - return false; - } - - infile.seekg(0, std::ios::beg); - content.resize(static_cast(fileSize)); - if (!infile.read(content.data(), fileSize)) { - ec = std::make_error_code(std::errc::io_error); - return false; - } - - return true; - }; - - std::string text; - if (!readFile(file_name, text, ec)) return false; - return parse_json_ec(text, out, ec); - } - - void check_json_assign_field(bool ok, const std::error_code& ec, const Psc::JSON *that_json, const char *name) { - if (!ok) { - std::ostringstream oss; - oss << "json assign error:[" << name << "," << Psc::platform_2_utf8(ec.message()) << "]"; - if (that_json != nullptr) { - oss << " from" << that_json->to_json_string(); - } - oss << std::endl; - throw json_assign_error(ec, oss.str()); - } - } - } // namespace Psc + oss << std::endl; + throw json_assign_error(ec, oss.str()); + } +} +} // namespace Psc #undef HANDLE_ERROR - #ifdef _USE_GTEST -#include #include #include +#include #include #include #include @@ -521,37 +565,31 @@ namespace Psc { namespace { -std::string compact_json(const Psc::JSON& json) { - return json.to_json_string("", "", "", 0); +std::string compact_json(const Psc::JSON &json) { + return json.to_json_string("", "", "", 0); } struct TempFileGuard { - const char* path; + const char *path; - ~TempFileGuard() { - std::remove(path); - } + ~TempFileGuard() { std::remove(path); } }; struct JsonCase { - const char* name; - const char* text; + const char *name; + const char *text; }; -const std::vector& json_cases() { - static const std::vector cases = { - { - "object_basic", - R"({ +const std::vector &json_cases() { + static const std::vector cases = {{"object_basic", + R"({ "name": "psc", "debug": true, "version": 1, "empty": null - })" - }, - { - "nested_object", - R"({ + })"}, + {"nested_object", + R"({ "project": { "name": "psc", "enabled": true, @@ -562,22 +600,18 @@ const std::vector& json_cases() { } }, "status": "ok" - })" - }, - { - "array_with_objects", - R"({ + })"}, + {"array_with_objects", + R"({ "users": [ {"name": "tom", "admin": true}, {"name": "jerry", "admin": false}, {"name": "alice", "admin": true} ], "count": 3 - })" - }, - { - "deep_mixed", - R"({ + })"}, + {"deep_mixed", + R"({ "app": { "name": "server", "modules": [ @@ -605,11 +639,9 @@ const std::vector& json_cases() { }, "ok": true, "none": null - })" - }, - { - "root_array", - R"([ + })"}, + {"root_array", + R"([ { "name": "one", "value": 1, @@ -629,78 +661,72 @@ const std::vector& json_cases() { false, 123, "text" - ])" - } - }; + ])"}}; - return cases; + return cases; } -void assert_parse_ok(const char* text, Psc::JSON& out) { - std::error_code ec; - ASSERT_TRUE(Psc::parse_json_ec(text, out, ec)) << ec.message(); - ASSERT_FALSE(ec) << ec.message(); +void assert_parse_ok(const char *text, Psc::JSON &out) { + std::error_code ec; + ASSERT_TRUE(Psc::parse_json_ec(text, out, ec)) << ec.message(); + ASSERT_FALSE(ec) << ec.message(); } -void assert_round_trip(const char* text) { - Psc::JSON first; - assert_parse_ok(text, first); +void assert_round_trip(const char *text) { + Psc::JSON first; + assert_parse_ok(text, first); - const std::string first_text = compact_json(first); + const std::string first_text = compact_json(first); - Psc::JSON second; - assert_parse_ok(first_text.c_str(), second); + Psc::JSON second; + assert_parse_ok(first_text.c_str(), second); - const std::string second_text = compact_json(second); + const std::string second_text = compact_json(second); - EXPECT_EQ(second_text, first_text); + EXPECT_EQ(second_text, first_text); } } // namespace - TEST(JSONTest, ParseAndRoundTripComplexJsonList) { - for (const JsonCase& item : json_cases()) { - SCOPED_TRACE(item.name); - assert_round_trip(item.text); - } + for (const JsonCase &item : json_cases()) { + SCOPED_TRACE(item.name); + assert_round_trip(item.text); + } } - TEST(JSONTest, ParseObjectAndGetFields) { - Psc::JSON json; - assert_parse_ok( - R"({ + Psc::JSON json; + assert_parse_ok( + R"({ "name": "psc", "debug": true, "version": 1, "empty": null })", - json - ); + json); - EXPECT_TRUE(json.has("name")); - EXPECT_TRUE(json.has("debug")); - EXPECT_TRUE(json.has("version")); - EXPECT_TRUE(json.has("empty")); - EXPECT_FALSE(json.has("missing")); + EXPECT_TRUE(json.has("name")); + EXPECT_TRUE(json.has("debug")); + EXPECT_TRUE(json.has("version")); + EXPECT_TRUE(json.has("empty")); + EXPECT_FALSE(json.has("missing")); - std::error_code ec; + std::error_code ec; - std::string name; - ASSERT_TRUE(json.get_string_ec("name", name, ec)); - EXPECT_EQ(name, "psc"); + std::string name; + ASSERT_TRUE(json.get_string_ec("name", name, ec)); + EXPECT_EQ(name, "psc"); - bool debug = false; - ASSERT_TRUE(json.get_bool_ec("debug", debug, ec)); - EXPECT_TRUE(debug); + bool debug = false; + ASSERT_TRUE(json.get_bool_ec("debug", debug, ec)); + EXPECT_TRUE(debug); } - TEST(JSONTest, ParseNestedObjectAndGetTopFields) { - Psc::JSON json; - assert_parse_ok( - R"({ + Psc::JSON json; + assert_parse_ok( + R"({ "project": { "name": "psc", "enabled": true, @@ -711,173 +737,163 @@ TEST(JSONTest, ParseNestedObjectAndGetTopFields) { }, "status": "ok" })", - json - ); + json); - EXPECT_TRUE(json.has("project")); - EXPECT_TRUE(json.has("status")); + EXPECT_TRUE(json.has("project")); + EXPECT_TRUE(json.has("status")); - std::error_code ec; - std::string status; + std::error_code ec; + std::string status; - ASSERT_TRUE(json.get_string_ec("status", status, ec)); - EXPECT_EQ(status, "ok"); + ASSERT_TRUE(json.get_string_ec("status", status, ec)); + EXPECT_EQ(status, "ok"); - const Psc::JSON* project = json.get("project"); - ASSERT_NE(project, nullptr); + const Psc::JSON *project = json.get("project"); + ASSERT_NE(project, nullptr); - EXPECT_TRUE(project->has("name")); - EXPECT_TRUE(project->has("enabled")); - EXPECT_TRUE(project->has("config")); + EXPECT_TRUE(project->has("name")); + EXPECT_TRUE(project->has("enabled")); + EXPECT_TRUE(project->has("config")); - std::string project_name; - ASSERT_TRUE(project->get_string_ec("name", project_name, ec)); - EXPECT_EQ(project_name, "psc"); + std::string project_name; + ASSERT_TRUE(project->get_string_ec("name", project_name, ec)); + EXPECT_EQ(project_name, "psc"); - bool enabled = false; - ASSERT_TRUE(project->get_bool_ec("enabled", enabled, ec)); - EXPECT_TRUE(enabled); + bool enabled = false; + ASSERT_TRUE(project->get_bool_ec("enabled", enabled, ec)); + EXPECT_TRUE(enabled); } - TEST(JSONTest, CopyConstructorKeepsComplexJson) { - for (const JsonCase& item : json_cases()) { - SCOPED_TRACE(item.name); + for (const JsonCase &item : json_cases()) { + SCOPED_TRACE(item.name); - Psc::JSON original; - assert_parse_ok(item.text, original); + Psc::JSON original; + assert_parse_ok(item.text, original); - const std::string expected = compact_json(original); + const std::string expected = compact_json(original); - Psc::JSON copied(original); + Psc::JSON copied(original); - EXPECT_EQ(compact_json(copied), expected); + EXPECT_EQ(compact_json(copied), expected); - original = Psc::JSON{}; - assert_parse_ok(R"({"changed":true})", original); + original = Psc::JSON{}; + assert_parse_ok(R"({"changed":true})", original); - EXPECT_EQ(compact_json(copied), expected); - } + EXPECT_EQ(compact_json(copied), expected); + } } - TEST(JSONTest, CopyAssignmentKeepsComplexJson) { - for (const JsonCase& item : json_cases()) { - SCOPED_TRACE(item.name); + for (const JsonCase &item : json_cases()) { + SCOPED_TRACE(item.name); - Psc::JSON source; - Psc::JSON target; + Psc::JSON source; + Psc::JSON target; - assert_parse_ok(item.text, source); - assert_parse_ok(R"({"old":false})", target); + assert_parse_ok(item.text, source); + assert_parse_ok(R"({"old":false})", target); - const std::string expected = compact_json(source); + const std::string expected = compact_json(source); - target = source; + target = source; - EXPECT_EQ(compact_json(target), expected); + EXPECT_EQ(compact_json(target), expected); - source = Psc::JSON{}; - assert_parse_ok(R"({"changed":true})", source); + source = Psc::JSON{}; + assert_parse_ok(R"({"changed":true})", source); - EXPECT_EQ(compact_json(target), expected); - } + EXPECT_EQ(compact_json(target), expected); + } } - TEST(JSONTest, MoveConstructorKeepsComplexJson) { - for (const JsonCase& item : json_cases()) { - SCOPED_TRACE(item.name); + for (const JsonCase &item : json_cases()) { + SCOPED_TRACE(item.name); - Psc::JSON source; - assert_parse_ok(item.text, source); + Psc::JSON source; + assert_parse_ok(item.text, source); - const std::string expected = compact_json(source); + const std::string expected = compact_json(source); - Psc::JSON moved(std::move(source)); + Psc::JSON moved(std::move(source)); - EXPECT_EQ(compact_json(moved), expected); - } + EXPECT_EQ(compact_json(moved), expected); + } } - TEST(JSONTest, MoveAssignmentKeepsComplexJson) { - for (const JsonCase& item : json_cases()) { - SCOPED_TRACE(item.name); + for (const JsonCase &item : json_cases()) { + SCOPED_TRACE(item.name); - Psc::JSON source; - Psc::JSON target; + Psc::JSON source; + Psc::JSON target; - assert_parse_ok(item.text, source); - assert_parse_ok(R"({"old":false})", target); + assert_parse_ok(item.text, source); + assert_parse_ok(R"({"old":false})", target); - const std::string expected = compact_json(source); + const std::string expected = compact_json(source); - target = std::move(source); + target = std::move(source); - EXPECT_EQ(compact_json(target), expected); - } + EXPECT_EQ(compact_json(target), expected); + } } - TEST(JSONTest, SelfCopyAssignmentKeepsComplexJson) { - for (const JsonCase& item : json_cases()) { - SCOPED_TRACE(item.name); + for (const JsonCase &item : json_cases()) { + SCOPED_TRACE(item.name); - Psc::JSON json; - assert_parse_ok(item.text, json); + Psc::JSON json; + assert_parse_ok(item.text, json); - const std::string expected = compact_json(json); + const std::string expected = compact_json(json); - json = json; + json = json; - EXPECT_EQ(compact_json(json), expected); - } + EXPECT_EQ(compact_json(json), expected); + } } - TEST(JSONTest, GetMissingFieldReturnsError) { - Psc::JSON json; - assert_parse_ok(R"({"name":"psc"})", json); + Psc::JSON json; + assert_parse_ok(R"({"name":"psc"})", json); - std::error_code ec; - std::string value; + std::error_code ec; + std::string value; - EXPECT_FALSE(json.get_string_ec("missing", value, ec)); - EXPECT_EQ(ec, std::make_error_code(std::errc::invalid_argument)); + EXPECT_FALSE(json.get_string_ec("missing", value, ec)); + EXPECT_EQ(ec, std::make_error_code(std::errc::invalid_argument)); } - TEST(JSONTest, GetBoolFromNonBoolReturnsError) { - Psc::JSON json; - assert_parse_ok(R"({"name":"psc"})", json); + Psc::JSON json; + assert_parse_ok(R"({"name":"psc"})", json); - std::error_code ec; - bool value = false; + std::error_code ec; + bool value = false; - EXPECT_FALSE(json.get_bool_ec("name", value, ec)); - EXPECT_EQ(ec, std::make_error_code(std::errc::invalid_argument)); + EXPECT_FALSE(json.get_bool_ec("name", value, ec)); + EXPECT_EQ(ec, std::make_error_code(std::errc::invalid_argument)); } - TEST(JSONTest, ParseInvalidJsonReturnsError) { - Psc::JSON json; - std::error_code ec; + Psc::JSON json; + std::error_code ec; - EXPECT_FALSE(Psc::parse_json_ec("x", json, ec)); - EXPECT_EQ(ec, std::make_error_code(std::errc::invalid_argument)); + EXPECT_FALSE(Psc::parse_json_ec("x", json, ec)); + EXPECT_EQ(ec, std::make_error_code(std::errc::invalid_argument)); } - TEST(JSONTest, ParseJsonFileComplex) { - constexpr const char* file_name = "psc_json_gtest_tmp.json"; - TempFileGuard guard{file_name}; + constexpr const char *file_name = "psc_json_gtest_tmp.json"; + TempFileGuard guard{file_name}; - { - std::ofstream ofs(file_name, std::ios::binary); - ASSERT_TRUE(ofs.is_open()); + { + std::ofstream ofs(file_name, std::ios::binary); + ASSERT_TRUE(ofs.is_open()); - ofs << R"({ + ofs << R"({ "app": { "name": "file_test", "enabled": true, @@ -888,44 +904,40 @@ TEST(JSONTest, ParseJsonFileComplex) { }, "ok": true })"; - } + } - Psc::JSON json; - std::error_code ec; + Psc::JSON json; + std::error_code ec; - ASSERT_TRUE(Psc::parse_json_file_ec(file_name, json, ec)) << ec.message(); + ASSERT_TRUE(Psc::parse_json_file_ec(file_name, json, ec)) << ec.message(); - EXPECT_TRUE(json.has("app")); - EXPECT_TRUE(json.has("ok")); + EXPECT_TRUE(json.has("app")); + EXPECT_TRUE(json.has("ok")); - bool ok = false; - ASSERT_TRUE(json.get_bool_ec("ok", ok, ec)); - EXPECT_TRUE(ok); + bool ok = false; + ASSERT_TRUE(json.get_bool_ec("ok", ok, ec)); + EXPECT_TRUE(ok); - const Psc::JSON* app = json.get("app"); - ASSERT_NE(app, nullptr); + const Psc::JSON *app = json.get("app"); + ASSERT_NE(app, nullptr); - std::string name; - ASSERT_TRUE(app->get_string_ec("name", name, ec)); - EXPECT_EQ(name, "file_test"); + std::string name; + ASSERT_TRUE(app->get_string_ec("name", name, ec)); + EXPECT_EQ(name, "file_test"); - bool enabled = false; - ASSERT_TRUE(app->get_bool_ec("enabled", enabled, ec)); - EXPECT_TRUE(enabled); + bool enabled = false; + ASSERT_TRUE(app->get_bool_ec("enabled", enabled, ec)); + EXPECT_TRUE(enabled); } - TEST(JSONTest, ParseMissingFileReturnsError) { - Psc::JSON json; - std::error_code ec; + Psc::JSON json; + std::error_code ec; - EXPECT_FALSE(Psc::parse_json_file_ec( - "__not_exist_psc_json_test_file__.json", - json, - ec - )); + EXPECT_FALSE(Psc::parse_json_file_ec("__not_exist_psc_json_test_file__.json", + json, ec)); - EXPECT_EQ(ec, std::make_error_code(std::errc::no_such_file_or_directory)); + EXPECT_EQ(ec, std::make_error_code(std::errc::no_such_file_or_directory)); } #endif \ No newline at end of file diff --git a/Core/Base/JSON.h b/Core/Base/JSON.h index fc7103e..ec8934f 100644 --- a/Core/Base/JSON.h +++ b/Core/Base/JSON.h @@ -1,7 +1,7 @@ #pragma once -#include "../system/export.h" #include "../Base/global_include.h" +#include "../system/export.h" #include #include #include @@ -10,27 +10,24 @@ #include #include -#define PSC_JSON_KEY_PARAMS(M, SEP) \ - M(const std::string&, key) +#define PSC_JSON_KEY_PARAMS(M, SEP) M(const std::string &, key) -#define PSC_JSON_PARSE_PARAMS(M, SEP) \ - M(const std::string&, text) +#define PSC_JSON_PARSE_PARAMS(M, SEP) M(const std::string &, text) -#define PSC_JSON_FILE_PARAMS(M, SEP) \ - M(const std::string&, file_name) +#define PSC_JSON_FILE_PARAMS(M, SEP) M(const std::string &, file_name) #undef max #undef min -#define Json_GET(type, name) \ - [[nodiscard]] type get_##name(const std::string &_key) const { \ - const Psc::JSON *that = get(_key); \ - if (!that) { \ - std::cout << "get" #type " error json not found! key:" << _key << " json: " << to_json_string() \ - << std::endl; \ - return false; \ - } \ - return that->name##_val(); \ - } +#define Json_GET(type, name) \ + [[nodiscard]] type get_##name(const std::string &_key) const { \ + const Psc::JSON *that = get(_key); \ + if (!that) { \ + std::cout << "get" #type " error json not found! key:" << _key \ + << " json: " << to_json_string() << std::endl; \ + return false; \ + } \ + return that->name##_val(); \ + } #pragma once #include "../Base/global_include.h" @@ -40,462 +37,475 @@ #include #include - - - namespace Psc { +class json_assign_error final : public std::system_error { +public: + using std::system_error::system_error; +}; +enum JsonType : uint8_t { String, Object, Array, Null, Number, Bool }; +template void assign_json(JsonType &rt, std::string &rv, T &&val); +template +bool to_number_ec(const std::string &val, T_Number &out, + std::error_code &ec) noexcept; - class json_assign_error final : public std::system_error { - public: - using std::system_error::system_error; - }; +template T_Number to_number(const std::string &val) { + return detail::triple_api_throwing( + [&val](T_Number &out, std::error_code &ec) { + return to_number_ec(val, out, ec); + }, + "to_number failed"); +} - enum JsonType : uint8_t { String, Object, Array, Null, Number, Bool }; - template void assign_json(JsonType& rt, std::string& rv, T&& val); - template - bool to_number_ec(const std::string& val, T_Number& out, std::error_code& ec) noexcept; +template +expected +try_to_number(const std::string &val) noexcept { + return detail::triple_api_expected( + [&val](T_Number &out, std::error_code &ec) { + return to_number_ec(val, out, ec); + }); +} - template - T_Number to_number(const std::string& val) { - return detail::triple_api_throwing( - [&val](T_Number& out, std::error_code& ec) { - return to_number_ec(val, out, ec); - }, - "to_number failed"); - } +template +bool to_number_ec(const std::string &val, T_Number &out, + std::error_code &ec) noexcept { + ec.clear(); + // 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全) + static_assert(std::is_integral_v || + std::is_floating_point_v, + "to_number: T_Number must be an integral or " + "floating-point type"); - template - expected try_to_number(const std::string& val) noexcept { - return detail::triple_api_expected( - [&val](T_Number& out, std::error_code& ec) { - return to_number_ec(val, out, ec); - }); - } - - template - bool to_number_ec(const std::string& val, T_Number& out, std::error_code& ec) noexcept { - ec.clear(); - // 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全) - static_assert(std::is_integral_v || std::is_floating_point_v, - "to_number: T_Number must be an integral or floating-point type"); - - try { - if constexpr (std::is_integral_v) { - if constexpr (std::is_unsigned_v) { - // stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range - unsigned long long x = std::stoull(val); - // 额外范围检查,避免静默截断 - if (x > static_cast(std::numeric_limits::max())) { - ec = std::make_error_code(std::errc::result_out_of_range); - return false; - } - out = static_cast(x); - return true; - } else { - long long x = std::stoll(val); - // 额外范围检查,避免静默截断 - if (x < static_cast(std::numeric_limits::min()) || - x > static_cast(std::numeric_limits::max())) { - ec = std::make_error_code(std::errc::result_out_of_range); - return false; - } - out = static_cast(x); - return true; - } - } else { // floating point - long double x = std::stold(val); - // 可选:检查是否超出目标浮点类型范围 - if (x < -static_cast(std::numeric_limits::max()) || - x > static_cast(std::numeric_limits::max())) { - ec = std::make_error_code(std::errc::result_out_of_range); - return false; - } - out = static_cast(x); - return true; - } - } catch (const std::invalid_argument&) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; // 不能解析为数字 - } catch (const std::out_of_range&) { - ec = std::make_error_code(std::errc::result_out_of_range); - return false; // 数值超范围 - } - } - - - - class JSON { - public: - static std::function handle_error; - explicit operator std::string() const; - friend std::ostream &operator<<(std::ostream &os, const JSON &obj); - - - - - [[nodiscard]] bool has(const std::string &key) const; - [[nodiscard]] const JSON *get(const std::string &key) const; - - - PSC_DECLARE_TRIPLE_API_CONST_METHOD(std::string, get_string, PSC_JSON_KEY_PARAMS); - PSC_DECLARE_TRIPLE_API_CONST_METHOD_0(bool, bool_val); - PSC_DECLARE_TRIPLE_API_CONST_METHOD(bool, get_bool, PSC_JSON_KEY_PARAMS); - - template - T_Number get_number(const std::string& key) const { - return detail::triple_api_throwing( - [this, &key](T_Number& out, std::error_code& ec) { - return get_number_ec(key, out, ec); - }, - "get_number failed"); - } - - template - expected try_get_number(const std::string& key) const noexcept { - return detail::triple_api_expected( - [this, &key](T_Number& out, std::error_code& ec) { - return get_number_ec(key, out, ec); - }); - } - - template - bool get_number_ec(const std::string& key, T_Number& out, std::error_code& ec) const noexcept { - const JSON *that = get(key); - if (!that) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - return that->number_val_ec(out, ec); - } - - template - T_Number number_val() const { - return detail::triple_api_throwing( - [this](T_Number& out, std::error_code& ec) { - return number_val_ec(out, ec); - }, - "number_val failed"); - } - - template - expected try_number_val() const noexcept { - return detail::triple_api_expected( - [this](T_Number& out, std::error_code& ec) { - return number_val_ec(out, ec); - }); - } - - template - bool number_val_ec(T_Number& out, std::error_code& ec) const noexcept { - if (valueType != Number) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - return to_number_ec(val, out, ec); - } - - - JSON(std::string key, const JSON &body); - template , JSON>>> - JSON(std::string k, T&& v) { - key = std::move(k); - assign_json( valueType, val , std::forward(v)); - } - template , JSON>>> - JSON(T&& v) { - assign_json( valueType, val , std::forward(v)); - } - JSON(); - JSON(const JSON& other); - JSON(JSON&& other) noexcept; - JSON& operator=(const JSON& other); - JSON& operator=(JSON&& other) noexcept; - - - void append_list(const std::vector &arr); - void append(const JSON &json); - void prepend(const JSON &json); - static JSON array(std::string key, const std::vector &arr); - static JSON object(std::string key, const std::vector &children); - static JSON array(const std::vector &arr = {}); - static JSON object(const std::vector &children = {}); - JsonType valueType = Null; - std::string key, val; - std::vector children; - [[nodiscard]] std::string to_json_string(const std::string &object_split = "\n", - const std::string &array_split = "\n", - const std::string &indentStr = " ", const int &indent = 0) const; - - private: - static std::string get_indent(const int &indent, const std::string &indentStr); - void append_value_string(std::string &ret, const int &indent, bool isEnd, const std::string &object_split, - const std::string &array_split, const std::string &indentStr, - JsonType fatherType) const; - }; - - - - - PSC_DECLARE_TRIPLE_API(JSON, parse_json, PSC_JSON_PARSE_PARAMS); - PSC_DECLARE_TRIPLE_API(JSON, parse_json_file, PSC_JSON_FILE_PARAMS); - - - - - template void assign_json(JsonType& rt, std::string& rv, T &&v) { - using C = std::decay_t; - if constexpr (std::is_same_v) { - rt = String; - rv = std::forward(v); - } - else if constexpr (std::is_same_v) { - std::stringstream ss; - ss << "0x" << std::setw(sizeof(void*) * 2) << std::setfill('0') << std::hex << - reinterpret_cast(v); - rt = String; - rv = ss.str(); - } - // 处理 char* 类型 - else if constexpr (std::is_same_v) { - rt = String; - rv = std::string(v); - } - else if constexpr (std::is_same_v) { - rt = String; - rv = std::string(v); // 或 val = v; - } - // 处理 wchar_t* 类型 - else if constexpr (std::is_same_v) { - std::wstring ws(v); - rt = String; - rv = std::string(ws.begin(), ws.end()); - } - // 处理 std::wstring 类型 - else if constexpr (std::is_same_v) { - rt = String; - rv = std::string(v.begin(), v.end()); - } - // 处理枚举类型 - else if constexpr (std::is_enum_v) { - rt = String; - rv = std::string(magic_enum::enum_name(v)); - } - // 处理 bool 类型 - else if constexpr (std::is_same_v) { - rt = Bool; - rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换 - } - // 处理 std::nullptr_t 类型 - else if constexpr (std::is_same_v) { - rt = Null; - rv = "null"; - } - else if constexpr (std::is_arithmetic_v) { - rt = Number; - rv = std::to_string(v); - } - else if constexpr (is_atomic_v) { - assign_json(rt, rv, v.load()); - } - else if constexpr (is_optional_v) { - if (v.has_value()) { - assign_json(rt, rv, v.value()); - } else { - rt = Null; - rv = "null"; - } - } - else { - rt = String; - rv = v.to_string(); - } - } - template - bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name, std::error_code& ec) noexcept; - - template - void assign_field(T& field, const Psc::JSON* that_json, const char* name) { - detail::triple_api_throwing_void( - [&field, that_json, name](std::error_code& ec) { - return assign_field_ec(field, that_json, name, ec); - }, - "assign_field failed"); - } - - template - expected try_assign_field(T& field, const Psc::JSON* that_json, const char* name) noexcept { - return detail::triple_api_expected_void( - [&field, that_json, name](std::error_code& ec) { - return assign_field_ec(field, that_json, name, ec); - }); - } - - template - bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name, std::error_code& ec) noexcept { - using C = clean_t; - if (that_json == nullptr) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - auto j = that_json->get(name); - if (j == nullptr) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - - if constexpr (std::is_same_v) { - return j->bool_val_ec(field, ec); - } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { - return that_json->get_number_ec(name, field, ec); - } else if constexpr (std::is_same_v) { - return that_json->get_string_ec(name, field, ec); - } else if constexpr (std::is_enum_v) { - std::string value; - if (!that_json->get_string_ec(name, value, ec)) return false; - field = Psc::to_enum(value); - } else if constexpr (is_atomic_v) { - using V = atomic_value_t; - V value{}; - if constexpr (std::is_same_v) { - if (!that_json->get_bool_ec(name, value, ec)) return false; - } else if constexpr (std::is_arithmetic_v) { - if (!that_json->get_number_ec(name, value, ec)) return false; - } - field = value; - } else if constexpr (is_optional_v) { - using V = optional_value_t; - V value{}; - if constexpr (std::is_same_v) { - if (!that_json->get_bool_ec(name, value, ec)) return false; - } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { - if (!that_json->get_number_ec(name, value, ec)) return false; - } else if constexpr (std::is_same_v) { - if (!that_json->get_string_ec(name, value, ec)) return false; - } else if constexpr (std::is_enum_v) { - std::string text; - if (!that_json->get_string_ec(name, text, ec)) return false; - value = Psc::to_enum(text); - } else { - static_assert(!sizeof(T), "assign_field does not support this optional type"); - } - field = std::move(value); - } else { - static_assert(!sizeof(T), "assign_field does not support this type"); + try { + if constexpr (std::is_integral_v) { + if constexpr (std::is_unsigned_v) { + // stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range + unsigned long long x = std::stoull(val); + // 额外范围检查,避免静默截断 + if (x > static_cast( + std::numeric_limits::max())) { + ec = std::make_error_code(std::errc::result_out_of_range); + return false; } + out = static_cast(x); return true; + } else { + long long x = std::stoll(val); + // 额外范围检查,避免静默截断 + if (x < static_cast(std::numeric_limits::min()) || + x > static_cast(std::numeric_limits::max())) { + ec = std::make_error_code(std::errc::result_out_of_range); + return false; + } + out = static_cast(x); + return true; + } + } else { // floating point + long double x = std::stold(val); + // 可选:检查是否超出目标浮点类型范围 + if (x < -static_cast(std::numeric_limits::max()) || + x > static_cast(std::numeric_limits::max())) { + ec = std::make_error_code(std::errc::result_out_of_range); + return false; + } + out = static_cast(x); + return true; } + } catch (const std::invalid_argument &) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; // 不能解析为数字 + } catch (const std::out_of_range &) { + ec = std::make_error_code(std::errc::result_out_of_range); + return false; // 数值超范围 + } +} - template void output_field(const T &field, Psc::JSON &ret, const char *name) { - using C = clean_t; - // bool +class JSON { +public: + static std::function + handle_error; + explicit operator std::string() const; + friend std::ostream &operator<<(std::ostream &os, const JSON &obj); - if constexpr (std::is_same_v) { - ret.append(Psc::JSON(name, field)); - } - // 数字(排除 bool) - else if constexpr (std::is_arithmetic_v && !std::is_same_v) { - ret.append(Psc::JSON(name, field)); - } - // string - else if constexpr (std::is_same_v) { - ret.append(Psc::JSON(name, field)); - } - // enum - else if constexpr (std::is_enum_v) { - ret.append(Psc::JSON(name, Psc::to_string(field))); - } - // atomic - else if constexpr (is_atomic_v) { - ret.append(Psc::JSON(name, field.load())); - } - // optional - else if constexpr (is_optional_v) { - using V = optional_value_t; - if (field.has_value()) { - // --- optional - if constexpr (std::is_same_v) { - ret.append(Psc::JSON(name, field.value())); - } - // --- optional - else if constexpr (std::is_arithmetic_v && !std::is_same_v) { - ret.append(Psc::JSON(name, field.value())); - } - // --- optional - else if constexpr (std::is_same_v) { - ret.append(Psc::JSON(name, field.value())); - } - // --- optional - else if constexpr (std::is_enum_v) { - ret.append(Psc::JSON(name, to_string(field.value()))); - } - // --- optional - else if constexpr (is_atomic_v) { - ret.append(Psc::JSON(name, field.value().load())); - } - // --- optional<未知类型>(调试输出) - else { - ret.append(Psc::JSON(name, field.value().to_string())); - } - } else { - // optional 没值 → JSON null - ret.append(Psc::JSON(name, nullptr)); - } - } - else if constexpr (is_shared_ptr_v) { - if (field) { - ret.append(Psc::JSON(name, field->to_string())); - } else { - ret.append(Psc::JSON(name, nullptr)); - } - } - // 最终兜底 - else { - ret.append(Psc::JSON(name, field.to_string())); - } + [[nodiscard]] bool has(const std::string &key) const; + [[nodiscard]] const JSON *get(const std::string &key) const; + + PSC_DECLARE_TRIPLE_API_CONST_METHOD(std::string, get_string, + PSC_JSON_KEY_PARAMS); + PSC_DECLARE_TRIPLE_API_CONST_METHOD_0(bool, bool_val); + PSC_DECLARE_TRIPLE_API_CONST_METHOD(bool, get_bool, PSC_JSON_KEY_PARAMS); + + template + T_Number get_number(const std::string &key) const { + return detail::triple_api_throwing( + [this, &key](T_Number &out, std::error_code &ec) { + return get_number_ec(key, out, ec); + }, + "get_number failed"); + } + + template + expected + try_get_number(const std::string &key) const noexcept { + return detail::triple_api_expected( + [this, &key](T_Number &out, std::error_code &ec) { + return get_number_ec(key, out, ec); + }); + } + + template + bool get_number_ec(const std::string &key, T_Number &out, + std::error_code &ec) const noexcept { + const JSON *that = get(key); + if (!that) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; } + return that->number_val_ec(out, ec); + } + template T_Number number_val() const { + return detail::triple_api_throwing( + [this](T_Number &out, std::error_code &ec) { + return number_val_ec(out, ec); + }, + "number_val failed"); + } - void check_json_assign_field(bool ok, const std::error_code& ec, const Psc::JSON *that_json, const char *name); + template + expected try_number_val() const noexcept { + return detail::triple_api_expected( + [this](T_Number &out, std::error_code &ec) { + return number_val_ec(out, ec); + }); + } + + template + bool number_val_ec(T_Number &out, std::error_code &ec) const noexcept { + if (valueType != Number) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + return to_number_ec(val, out, ec); + } + + JSON(std::string key, const JSON &body); + template , JSON>>> + JSON(std::string k, T &&v) { + key = std::move(k); + assign_json(valueType, val, std::forward(v)); + } + template , JSON>>> + JSON(T &&v) { + assign_json(valueType, val, std::forward(v)); + } + JSON(); + JSON(const JSON &other); + JSON(JSON &&other) noexcept; + JSON &operator=(const JSON &other); + JSON &operator=(JSON &&other) noexcept; + + void append_list(const std::vector &arr); + void append(const JSON &json); + void prepend(const JSON &json); + static JSON array(std::string key, const std::vector &arr); + static JSON object(std::string key, const std::vector &children); + static JSON array(const std::vector &arr = {}); + static JSON object(const std::vector &children = {}); + JsonType valueType = Null; + std::string key, val; + std::vector children; + [[nodiscard]] std::string + to_json_string(const std::string &object_split = "\n", + const std::string &array_split = "\n", + const std::string &indentStr = " ", + const int &indent = 0) const; + +private: + static std::string get_indent(const int &indent, + const std::string &indentStr); + void append_value_string(std::string &ret, const int &indent, bool isEnd, + const std::string &object_split, + const std::string &array_split, + const std::string &indentStr, + JsonType fatherType) const; +}; + +PSC_DECLARE_TRIPLE_API(JSON, parse_json, PSC_JSON_PARSE_PARAMS); +PSC_DECLARE_TRIPLE_API(JSON, parse_json_file, PSC_JSON_FILE_PARAMS); + +template void assign_json(JsonType &rt, std::string &rv, T &&v) { + using C = std::decay_t; + if constexpr (std::is_same_v) { + rt = String; + rv = std::forward(v); + } else if constexpr (std::is_same_v) { + std::stringstream ss; + ss << "0x" << std::setw(sizeof(void *) * 2) << std::setfill('0') << std::hex + << reinterpret_cast(v); + rt = String; + rv = ss.str(); + } + // 处理 char* 类型 + else if constexpr (std::is_same_v) { + rt = String; + rv = std::string(v); + } else if constexpr (std::is_same_v) { + rt = String; + rv = std::string(v); // 或 val = v; + } + // 处理 wchar_t* 类型 + else if constexpr (std::is_same_v) { + std::wstring ws(v); + rt = String; + rv = std::string(ws.begin(), ws.end()); + } + // 处理 std::wstring 类型 + else if constexpr (std::is_same_v) { + rt = String; + rv = std::string(v.begin(), v.end()); + } + // 处理枚举类型 + else if constexpr (std::is_enum_v) { + rt = String; + rv = std::string(magic_enum::enum_name(v)); + } + // 处理 bool 类型 + else if constexpr (std::is_same_v) { + rt = Bool; + rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换 + } + // 处理 std::nullptr_t 类型 + else if constexpr (std::is_same_v) { + rt = Null; + rv = "null"; + } else if constexpr (std::is_arithmetic_v) { + rt = Number; + rv = std::to_string(v); + } else if constexpr (is_atomic_v) { + assign_json(rt, rv, v.load()); + } else if constexpr (is_optional_v) { + if (v.has_value()) { + assign_json(rt, rv, v.value()); + } else { + rt = Null; + rv = "null"; + } + } else { + rt = String; + rv = v.to_string(); + } +} +template +bool assign_field_ec(T &field, const Psc::JSON *that_json, const char *name, + std::error_code &ec) noexcept; + +template +void assign_field(T &field, const Psc::JSON *that_json, const char *name) { + detail::triple_api_throwing_void( + [&field, that_json, name](std::error_code &ec) { + return assign_field_ec(field, that_json, name, ec); + }, + "assign_field failed"); +} + +template +expected try_assign_field(T &field, + const Psc::JSON *that_json, + const char *name) noexcept { + return detail::triple_api_expected_void( + [&field, that_json, name](std::error_code &ec) { + return assign_field_ec(field, that_json, name, ec); + }); +} + +template +bool assign_field_ec(T &field, const Psc::JSON *that_json, const char *name, + std::error_code &ec) noexcept { + using C = clean_t; + if (that_json == nullptr) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + auto j = that_json->get(name); + if (j == nullptr) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + + if constexpr (std::is_same_v) { + return j->bool_val_ec(field, ec); + } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { + return that_json->get_number_ec(name, field, ec); + } else if constexpr (std::is_same_v) { + return that_json->get_string_ec(name, field, ec); + } else if constexpr (std::is_enum_v) { + std::string value; + if (!that_json->get_string_ec(name, value, ec)) + return false; + field = Psc::to_enum(value); + } else if constexpr (is_atomic_v) { + using V = atomic_value_t; + V value{}; + if constexpr (std::is_same_v) { + if (!that_json->get_bool_ec(name, value, ec)) + return false; + } else if constexpr (std::is_arithmetic_v) { + if (!that_json->get_number_ec(name, value, ec)) + return false; + } + field = value; + } else if constexpr (is_optional_v) { + using V = optional_value_t; + V value{}; + if constexpr (std::is_same_v) { + if (!that_json->get_bool_ec(name, value, ec)) + return false; + } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { + if (!that_json->get_number_ec(name, value, ec)) + return false; + } else if constexpr (std::is_same_v) { + if (!that_json->get_string_ec(name, value, ec)) + return false; + } else if constexpr (std::is_enum_v) { + std::string text; + if (!that_json->get_string_ec(name, text, ec)) + return false; + value = Psc::to_enum(text); + } else { + static_assert(!sizeof(T), + "assign_field does not support this optional type"); + } + field = std::move(value); + } else { + static_assert(!sizeof(T), "assign_field does not support this type"); + } + return true; +} + +template +void output_field(const T &field, Psc::JSON &ret, const char *name) { + using C = clean_t; + // bool + + if constexpr (std::is_same_v) { + ret.append(Psc::JSON(name, field)); + } + // 数字(排除 bool) + else if constexpr (std::is_arithmetic_v && !std::is_same_v) { + ret.append(Psc::JSON(name, field)); + } + // string + else if constexpr (std::is_same_v) { + ret.append(Psc::JSON(name, field)); + } + // enum + else if constexpr (std::is_enum_v) { + ret.append(Psc::JSON(name, Psc::to_string(field))); + } + // atomic + else if constexpr (is_atomic_v) { + ret.append(Psc::JSON(name, field.load())); + } + // optional + else if constexpr (is_optional_v) { + using V = optional_value_t; + if (field.has_value()) { + // --- optional + if constexpr (std::is_same_v) { + ret.append(Psc::JSON(name, field.value())); + } + // --- optional + else if constexpr (std::is_arithmetic_v && !std::is_same_v) { + ret.append(Psc::JSON(name, field.value())); + } + // --- optional + else if constexpr (std::is_same_v) { + ret.append(Psc::JSON(name, field.value())); + } + // --- optional + else if constexpr (std::is_enum_v) { + ret.append(Psc::JSON(name, to_string(field.value()))); + } + // --- optional + else if constexpr (is_atomic_v) { + ret.append(Psc::JSON(name, field.value().load())); + } + // --- optional<未知类型>(调试输出) + else { + ret.append(Psc::JSON(name, field.value().to_string())); + } + } else { + // optional 没值 → JSON null + ret.append(Psc::JSON(name, nullptr)); + } + } else if constexpr (is_shared_ptr_v) { + if (field) { + ret.append(Psc::JSON(name, field->to_string())); + } else { + ret.append(Psc::JSON(name, nullptr)); + } + } + // 最终兜底 + else { + ret.append(Psc::JSON(name, field.to_string())); + } +} + +void check_json_assign_field(bool ok, const std::error_code &ec, + const Psc::JSON *that_json, const char *name); } // namespace Psc - - - #undef Json_GET -#define Get_J(FIELD) { \ - std::error_code ec_##FIELD; \ - const bool ok_##FIELD = Psc::assign_field_ec(FIELD, that_json, #FIELD, ec_##FIELD); \ - Psc::check_json_assign_field(ok_##FIELD, ec_##FIELD, that_json, #FIELD); \ -} - -#define Ret_J(FIELD) Psc::output_field(FIELD, ret, #FIELD); - +#define Get_J(FIELD) \ + { \ + std::error_code ec_##FIELD; \ + const bool ok_##FIELD = \ + Psc::assign_field_ec(FIELD, that_json, #FIELD, ec_##FIELD); \ + Psc::check_json_assign_field(ok_##FIELD, ec_##FIELD, that_json, #FIELD); \ + } +#define Ret_J(FIELD) \ + { \ + Psc::output_field(FIELD, ret, #FIELD); \ + } #define JSON_KV(P) {#P, (P)} -#define JSON_KV_1(P1) JSON_KV(P1) -#define JSON_KV_2(P1,P2) JSON_KV_1(P1), JSON_KV(P2) -#define JSON_KV_3(P1,P2,P3) JSON_KV_2(P1,P2), JSON_KV(P3) -#define JSON_KV_4(P1,P2,P3,P4) JSON_KV_3(P1,P2,P3), JSON_KV(P4) -#define JSON_KV_5(P1,P2,P3,P4,P5) JSON_KV_4(P1,P2,P3,P4), JSON_KV(P5) -#define JSON_KV_6(P1,P2,P3,P4,P5,P6) JSON_KV_5(P1,P2,P3,P4,P5), JSON_KV(P6) -#define JSON_KV_7(P1,P2,P3,P4,P5,P6,P7) JSON_KV_6(P1,P2,P3,P4,P5,P6), JSON_KV(P7) -#define JSON_KV_8(P1,P2,P3,P4,P5,P6,P7,P8) JSON_KV_7(P1,P2,P3,P4,P5,P6,P7), JSON_KV(P8) -#define JSON_KV_9(P1,P2,P3,P4,P5,P6,P7,P8,P9) JSON_KV_8(P1,P2,P3,P4,P5,P6,P7,P8), JSON_KV(P9) -#define JSON_KV_10(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10) JSON_KV_9(P1,P2,P3,P4,P5,P6,P7,P8,P9), JSON_KV(P10) +#define JSON_KV_1(P1) JSON_KV(P1) +#define JSON_KV_2(P1, P2) JSON_KV_1(P1), JSON_KV(P2) +#define JSON_KV_3(P1, P2, P3) JSON_KV_2(P1, P2), JSON_KV(P3) +#define JSON_KV_4(P1, P2, P3, P4) JSON_KV_3(P1, P2, P3), JSON_KV(P4) +#define JSON_KV_5(P1, P2, P3, P4, P5) JSON_KV_4(P1, P2, P3, P4), JSON_KV(P5) +#define JSON_KV_6(P1, P2, P3, P4, P5, P6) \ + JSON_KV_5(P1, P2, P3, P4, P5), JSON_KV(P6) +#define JSON_KV_7(P1, P2, P3, P4, P5, P6, P7) \ + JSON_KV_6(P1, P2, P3, P4, P5, P6), JSON_KV(P7) +#define JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8) \ + JSON_KV_7(P1, P2, P3, P4, P5, P6, P7), JSON_KV(P8) +#define JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8), JSON_KV(P9) +#define JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9), JSON_KV(P10) -#define VAR_JSON_1(P1) Psc::JSON::object({ JSON_KV_1(P1) }) -#define VAR_JSON_2(P1,P2) Psc::JSON::object({ JSON_KV_2(P1,P2) }) -#define VAR_JSON_3(P1,P2,P3) Psc::JSON::object({ JSON_KV_3(P1,P2,P3) }) -#define VAR_JSON_4(P1,P2,P3,P4) Psc::JSON::object({ JSON_KV_4(P1,P2,P3,P4) }) -#define VAR_JSON_5(P1,P2,P3,P4,P5) Psc::JSON::object({ JSON_KV_5(P1,P2,P3,P4,P5) }) -#define VAR_JSON_6(P1,P2,P3,P4,P5,P6) Psc::JSON::object({ JSON_KV_6(P1,P2,P3,P4,P5,P6) }) -#define VAR_JSON_7(P1,P2,P3,P4,P5,P6,P7) Psc::JSON::object({ JSON_KV_7(P1,P2,P3,P4,P5,P6,P7) }) -#define VAR_JSON_8(P1,P2,P3,P4,P5,P6,P7,P8) Psc::JSON::object({ JSON_KV_8(P1,P2,P3,P4,P5,P6,P7,P8) }) -#define VAR_JSON_9(P1,P2,P3,P4,P5,P6,P7,P8,P9) Psc::JSON::object({ JSON_KV_9(P1,P2,P3,P4,P5,P6,P7,P8,P9) }) -#define VAR_JSON_10(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10) Psc::JSON::object({ JSON_KV_10(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10) }) \ No newline at end of file +#define VAR_JSON_1(P1) Psc::JSON::object({JSON_KV_1(P1)}) +#define VAR_JSON_2(P1, P2) Psc::JSON::object({JSON_KV_2(P1, P2)}) +#define VAR_JSON_3(P1, P2, P3) Psc::JSON::object({JSON_KV_3(P1, P2, P3)}) +#define VAR_JSON_4(P1, P2, P3, P4) \ + Psc::JSON::object({JSON_KV_4(P1, P2, P3, P4)}) +#define VAR_JSON_5(P1, P2, P3, P4, P5) \ + Psc::JSON::object({JSON_KV_5(P1, P2, P3, P4, P5)}) +#define VAR_JSON_6(P1, P2, P3, P4, P5, P6) \ + Psc::JSON::object({JSON_KV_6(P1, P2, P3, P4, P5, P6)}) +#define VAR_JSON_7(P1, P2, P3, P4, P5, P6, P7) \ + Psc::JSON::object({JSON_KV_7(P1, P2, P3, P4, P5, P6, P7)}) +#define VAR_JSON_8(P1, P2, P3, P4, P5, P6, P7, P8) \ + Psc::JSON::object({JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8)}) +#define VAR_JSON_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \ + Psc::JSON::object({JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9)}) +#define VAR_JSON_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \ + Psc::JSON::object({JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)}) \ No newline at end of file diff --git a/Core/Base/RingBuffer.hpp b/Core/Base/RingBuffer.hpp index acf58fa..a19f4c8 100644 --- a/Core/Base/RingBuffer.hpp +++ b/Core/Base/RingBuffer.hpp @@ -12,17 +12,17 @@ namespace Psc { - - // -------------------- utils -------------------- -template -bool is_pow2(Size_T x) { return x && ((x & (x - 1)) == 0); } +template bool is_pow2(Size_T x) { + return x && ((x & (x - 1)) == 0); +} -template -Size_T ceil_to_pow2(Size_T x) { - if (x <= 1) return 1; +template Size_T ceil_to_pow2(Size_T x) { + if (x <= 1) + return 1; --x; - for (Size_T i = 1; i < sizeof(Size_T) * 8; i <<= 1) x |= x >> i; + for (Size_T i = 1; i < sizeof(Size_T) * 8; i <<= 1) + x |= x >> i; return x + 1; } @@ -31,9 +31,9 @@ Size_T ceil_to_pow2(Size_T x) { // - mask = capacity - 1 // - used = (tail - head) & mask // - free = (capacity - 1) - used (浪费 1 字节) -template -class Base_RingBuffer { +template class Base_RingBuffer { static_assert(std::is_unsigned_v, "Size_T must be unsigned"); + public: Base_RingBuffer() = default; void init(Size_T min_capacity) { @@ -76,24 +76,25 @@ protected: void rollback_unsafe(Size_T n) { head = (head - n) & mask_; } - void write_bytes_unsafe(const void* data, Size_T len) { + void write_bytes_unsafe(const void *data, Size_T len) { const Size_T end = std::min(len, capacity - tail); std::memcpy(buf_.data() + tail, data, end); - std::memcpy(buf_.data(), static_cast(data) + end, len - end); + std::memcpy(buf_.data(), static_cast(data) + end, + len - end); tail = (tail + len) & mask_; } - void read_bytes_unsafe(void* out, Size_T len) { + void read_bytes_unsafe(void *out, Size_T len) { const Size_T end = std::min(len, capacity - head); std::memcpy(out, buf_.data() + head, end); - std::memcpy(static_cast(out) + end, buf_.data(), len - end); + std::memcpy(static_cast(out) + end, buf_.data(), len - end); head = (head + len) & mask_; } - void peek_bytes_unsafe(void* out, Size_T len) const { + void peek_bytes_unsafe(void *out, Size_T len) const { const Size_T end = std::min(len, capacity - head); std::memcpy(out, buf_.data() + head, end); - std::memcpy(static_cast(out) + end, buf_.data(), len - end); + std::memcpy(static_cast(out) + end, buf_.data(), len - end); } protected: @@ -113,64 +114,78 @@ public: static constexpr Size_T HEADER_SIZE = sizeof(Size_T); // 包模式:空间不够则整体失败(不拆包) - bool write(const void* src, Size_T len) { + bool write(const void *src, Size_T len) { std::lock_guard lock(this->mutex_); - if (len > (this->capacity - 1 - HEADER_SIZE)) return false; + if (len > (this->capacity - 1 - HEADER_SIZE)) + return false; const Size_T need = HEADER_SIZE + len; - if (this->free_space_unsafe() < need) return false; - this->write_bytes_unsafe(reinterpret_cast(&len), HEADER_SIZE); - if (len) this->write_bytes_unsafe(src, len); + if (this->free_space_unsafe() < need) + return false; + this->write_bytes_unsafe(reinterpret_cast(&len), HEADER_SIZE); + if (len) + this->write_bytes_unsafe(src, len); return true; } // out_len: in 代表 out 缓冲最大容量;out_len: out 代表实际读到的长度 - bool read(void* out, Size_T& out_len) { + bool read(void *out, Size_T &out_len) { std::lock_guard lock(this->mutex_); - if (this->empty()) return false; + if (this->empty()) + return false; Size_T msg_len = 0; - this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); + this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); const Size_T need = HEADER_SIZE + static_cast(msg_len); - if (this->used_space_unsafe() < need) return false; // 半包 + if (this->used_space_unsafe() < need) + return false; // 半包 - if (out_len < msg_len) return false; // 调用者提供的 out 不够大 + if (out_len < msg_len) + return false; // 调用者提供的 out 不够大 Size_T dummy = 0; - this->read_bytes_unsafe(reinterpret_cast(&dummy), HEADER_SIZE); - if (msg_len) this->read_bytes_unsafe(out, msg_len); + this->read_bytes_unsafe(reinterpret_cast(&dummy), HEADER_SIZE); + if (msg_len) + this->read_bytes_unsafe(out, msg_len); out_len = msg_len; return true; } // 只 peek 包头,不消费;成功返回 true,并写出 msg_len - bool peek_len(Size_T& msg_len) { + bool peek_len(Size_T &msg_len) { std::lock_guard lock(this->mutex_); - if (this->empty()) return false; - this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); + if (this->empty()) + return false; + this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); // 防御:坏包头(避免队列被毒化) - if (msg_len > (this->capacity - 1 - HEADER_SIZE)) return false; + if (msg_len > (this->capacity - 1 - HEADER_SIZE)) + return false; const Size_T need = HEADER_SIZE + msg_len; - if (this->used_space_unsafe() < need) return false; // 半包 + if (this->used_space_unsafe() < need) + return false; // 半包 return true; } // peek 下一条消息内容(不消费) // out_len: in 为 out 缓冲容量;out_len: out 为消息实际长度 - bool peek(void* out, Size_T& out_len) { + bool peek(void *out, Size_T &out_len) { std::lock_guard lock(this->mutex_); - if (this->empty()) return false; + if (this->empty()) + return false; Size_T msg_len = 0; - this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); + this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); - if (msg_len > (this->capacity - 1 - HEADER_SIZE)) return false; + if (msg_len > (this->capacity - 1 - HEADER_SIZE)) + return false; const Size_T need = HEADER_SIZE + msg_len; - if (this->used_space_unsafe() < need) return false; // 半包 - if (out_len < msg_len) return false; + if (this->used_space_unsafe() < need) + return false; // 半包 + if (out_len < msg_len) + return false; // 先临时把 head 向前偏移 HEADER_SIZE,再 peek msg_len 字节 // 不修改 head:用局部 off 来计算 @@ -181,7 +196,8 @@ public: const Size_T cap = this->capacity; const Size_T end = std::min(msg_len, cap - off); std::memcpy(out, this->buf_.data() + off, end); - std::memcpy(static_cast(out) + end, this->buf_.data(), msg_len - end); + std::memcpy(static_cast(out) + end, this->buf_.data(), + msg_len - end); out_len = msg_len; return true; @@ -191,16 +207,19 @@ public: // 成功返回 true;若空/半包/坏包头则 false bool skip_one() { std::lock_guard lock(this->mutex_); - if (this->empty()) return false; + if (this->empty()) + return false; Size_T msg_len = 0; - this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); + this->peek_bytes_unsafe(reinterpret_cast(&msg_len), HEADER_SIZE); // 防御:坏包头,避免队列被毒化 - if (msg_len > (this->capacity - 1 - HEADER_SIZE)) return false; + if (msg_len > (this->capacity - 1 - HEADER_SIZE)) + return false; const Size_T need = HEADER_SIZE + msg_len; - if (this->used_space_unsafe() < need) return false; // 半包 + if (this->used_space_unsafe() < need) + return false; // 半包 // 直接前移 head(不实际读数据) this->head = (this->head + need) & this->mask_; @@ -208,34 +227,38 @@ public: } // 仅丢弃/消费下一条消息的 payload 的前 n 字节(不拷贝) - // 用于“读一条大消息但分段处理”的场景:你先 peek_len/peek 拿到长度,再分段 consume - // 注意:它不会跳过 header;它假设你已经消费过 header 或者你自定义协议 + // 用于“读一条大消息但分段处理”的场景:你先 peek_len/peek 拿到长度,再分段 + // consume 注意:它不会跳过 header;它假设你已经消费过 header 或者你自定义协议 // 如果你只需要 skip 整包,用 skip_one() bool skip_bytes(Size_T n) { std::lock_guard lock(this->mutex_); - if (n == 0) return true; - if (this->used_space_unsafe() < n) return false; + if (n == 0) + return true; + if (this->used_space_unsafe() < n) + return false; this->head = (this->head + n) & this->mask_; return true; } - }; // -------------------- Stream mode -------------------- template class Stream_RingBuffer : public Base_RingBuffer { public: - bool write(const void* src, Size_T len) { - if (len == 0) return true; + bool write(const void *src, Size_T len) { + if (len == 0) + return true; std::lock_guard lock(this->mutex_); - if (this->free_space_unsafe() < len) return false; + if (this->free_space_unsafe() < len) + return false; this->write_bytes_unsafe(src, len); return true; } // out_len 代表要读多少;成功则读满 out_len - bool read(void* out, Size_T& out_len) { - if (out_len == 0) return true; + bool read(void *out, Size_T &out_len) { + if (out_len == 0) + return true; std::lock_guard lock(this->mutex_); if (this->used_space_unsafe() < out_len) { out_len = 0; @@ -246,69 +269,82 @@ public: } // peek 最多 out_len 字节(不消费);返回实际 peek 到的字节数 - Size_T peek_best_effort(void* out, Size_T max_len) { - if (max_len == 0) return 0; + Size_T peek_best_effort(void *out, Size_T max_len) { + if (max_len == 0) + return 0; std::lock_guard lock(this->mutex_); const Size_T can_read = this->used_space_unsafe(); const Size_T actual = std::min(max_len, can_read); - if (actual == 0) return 0; + if (actual == 0) + return 0; // 等价于从 head 开始 peek actual 字节 const Size_T end = std::min(actual, this->capacity - this->head); std::memcpy(out, this->buf_.data() + this->head, end); - std::memcpy(static_cast(out) + end, this->buf_.data(), actual - end); + std::memcpy(static_cast(out) + end, this->buf_.data(), + actual - end); return actual; } // peek 指定 out_len 字节(不消费);成功则返回 true 并保持 out_len 不变 - bool peek(void* out, Size_T out_len) { - if (out_len == 0) return true; + bool peek(void *out, Size_T out_len) { + if (out_len == 0) + return true; std::lock_guard lock(this->mutex_); - if (this->used_space_unsafe() < out_len) return false; + if (this->used_space_unsafe() < out_len) + return false; const Size_T end = std::min(out_len, this->capacity - this->head); std::memcpy(out, this->buf_.data() + this->head, end); - std::memcpy(static_cast(out) + end, this->buf_.data(), out_len - end); + std::memcpy(static_cast(out) + end, this->buf_.data(), + out_len - end); return true; } - // best effort:尽可能写入,返回实际写入字节数 - Size_T write_best_effort(const void* src, Size_T len) { - if (len == 0) return 0; + Size_T write_best_effort(const void *src, Size_T len) { + if (len == 0) + return 0; std::lock_guard lock(this->mutex_); const Size_T can_write = this->free_space_unsafe(); const Size_T actual = std::min(len, can_write); - if (actual) this->write_bytes_unsafe(src, actual); + if (actual) + this->write_bytes_unsafe(src, actual); return actual; } // best effort:尽可能读取,返回实际读取字节数 - Size_T read_best_effort(void* out, Size_T max_len) { - if (max_len == 0) return 0; + Size_T read_best_effort(void *out, Size_T max_len) { + if (max_len == 0) + return 0; std::lock_guard lock(this->mutex_); const Size_T can_read = this->used_space_unsafe(); const Size_T actual = std::min(max_len, can_read); - if (actual) this->read_bytes_unsafe(out, actual); + if (actual) + this->read_bytes_unsafe(out, actual); return actual; } // 丢弃/消费 n 字节(不拷贝);成功则返回 true bool skip(Size_T n) { - if (n == 0) return true; + if (n == 0) + return true; std::lock_guard lock(this->mutex_); - if (this->used_space_unsafe() < n) return false; + if (this->used_space_unsafe() < n) + return false; this->head = (this->head + n) & this->mask_; return true; } // best effort:尽可能丢弃,返回实际丢弃字节数 Size_T skip_best_effort(Size_T n) { - if (n == 0) return 0; + if (n == 0) + return 0; std::lock_guard lock(this->mutex_); const Size_T can = this->used_space_unsafe(); const Size_T actual = std::min(n, can); - if (actual) this->head = (this->head + actual) & this->mask_; + if (actual) + this->head = (this->head + actual) & this->mask_; return actual; } }; diff --git a/Core/Base/SM_RingBuffer.cpp b/Core/Base/SM_RingBuffer.cpp index d39cb0d..18bc621 100644 --- a/Core/Base/SM_RingBuffer.cpp +++ b/Core/Base/SM_RingBuffer.cpp @@ -1,217 +1,228 @@ #include "SM_RingBuffer.h" +#include "Core/Base/global_include.h" #include "Core/spdlog/export.h" #include "Core/transmit_protocol/Channel_Simulator/global.h" -#include "Core/Base/global_include.h" namespace Psc { - // 1. used_space 简化:利用无符号溢出特性或 mask - size_t SM_Base_RingBuffer::used_space() const { - // 统一使用 mask 处理回绕,消除 if 判断 - return (state->tail - state->head) & mask; +// 1. used_space 简化:利用无符号溢出特性或 mask +size_t SM_Base_RingBuffer::used_space() const { + // 统一使用 mask 处理回绕,消除 if 判断 + return (state->tail - state->head) & mask; +} + +// 2. free_space:保持浪费一个字节的策略,确保 tail 永远不会追上 head 导致重合 +size_t SM_Base_RingBuffer::free_space() const { + // 逻辑容量是 capacity - 1 + return (state->capacity - 1) - used_space(); +} + +// 3. 判定函数 +[[nodiscard]] bool SM_Base_RingBuffer::empty() const { + return state->head == state->tail; +} + +[[nodiscard]] bool SM_Base_RingBuffer::full() const { + // 如果 tail 的下一个位置是 head,则为满 + return ((state->tail + 1) & mask) == state->head; +} + +// 4. rollback 优化:同样使用 mask 替代 % +void SM_Base_RingBuffer::rollback(size_t n) { + // (head - n) 可能产生负数溢出,但在无符号下配合 mask 是正确的 + state->head = (state->head - n) & mask; +} +SM_Base_RingBuffer::SM_Base_RingBuffer(const std::string &name, size_t size) { + init(name, size); +} + +void SM_Base_RingBuffer::init(const std::string &name, size_t size) { + data_mutex.init(name + "_data_mutex"); + create_mutex.init(name + "_create_mutex"); + std::lock_guard lock(create_mutex); + + // --- 修改点 1: 确保数据区本身是 2 的幂 --- + size_t data_size_pow2 = ceilToPow2(size + 1); + size_t total_alloc_size = sizeof(SharedMemoryState) + data_size_pow2; + + bool ok; + std::ostringstream oss; + bool open = check_if_shared_memory_exists(name); + + if (open) { + // 注意:打开时也要使用计算出的 total_alloc_size + oss << "【打开共享内存】" << VAR_STR_3(name, total_alloc_size, size) + << std::endl; + ok = shm.open(name, total_alloc_size); + create = false; + } else { + oss << "【创建共享内存】" << VAR_STR_3(name, total_alloc_size, size) + << std::endl; + ok = shm.create(name, total_alloc_size); + create = true; + } + + if (!ok) { + std::cerr << oss.str() << "无法创建或打开共享内存!" << std::endl; + Psc::fail_fast(); + } + + state = reinterpret_cast(shm.data()); + uint8_t *raw = shm.data(); + + if (!open) { + // --- 修改点 2: 直接存储 2 的幂 --- + state->capacity = data_size_pow2; + state->head = 0; + state->tail = 0; + } else { + if (state->capacity == 0 || (state->capacity & mask) != 0) { + std::cerr << "致命错误:共享内存容量非法,必须为 2 的幂!" << std::endl; + Psc::fail_fast(); } + } - // 2. free_space:保持浪费一个字节的策略,确保 tail 永远不会追上 head 导致重合 - size_t SM_Base_RingBuffer::free_space() const { - // 逻辑容量是 capacity - 1 - return (state->capacity - 1) - used_space(); - } + // --- 修改点 3: 这里的 mask 赋值必须在获取 state 之后,无论 open 还是 create + // 都要执行 --- + mask = state->capacity - 1; + buffer = raw + sizeof(SharedMemoryState); - // 3. 判定函数 - [[nodiscard]] bool SM_Base_RingBuffer::empty() const { - return state->head == state->tail; - } + // 打印调试信息 + oss.str(""); // 清空 + oss << "\t实际分配容量 (2^n): " << state->capacity << std::endl; + oss << "\tMask: " << std::hex << mask << std::dec << std::endl; + std::cout << oss.str(); +} - [[nodiscard]] bool SM_Base_RingBuffer::full() const { - // 如果 tail 的下一个位置是 head,则为满 - return ((state->tail + 1) & mask) == state->head; - } +SM_Base_RingBuffer::SM_Base_RingBuffer() = default; +SM_Base_RingBuffer::~SM_Base_RingBuffer() { + // 尤其注意不要删除共享内存删除会导致共享内存很奇怪 + shm.close(); // 关闭共享内存 +} +std::string SM_Base_RingBuffer::state_str() { + return std::to_string(state->head) + "," + std::to_string(state->tail) + "," + + std::to_string(state->capacity); +} +void SM_Base_RingBuffer::write_bytes(const uint8_t *data, size_t len) { + // 计算到缓冲区末尾的距离 + size_t end = std::min(len, state->capacity - state->tail); - // 4. rollback 优化:同样使用 mask 替代 % - void SM_Base_RingBuffer::rollback(size_t n) { - // (head - n) 可能产生负数溢出,但在无符号下配合 mask 是正确的 - state->head = (state->head - n) & mask; - } - SM_Base_RingBuffer::SM_Base_RingBuffer(const std::string &name, size_t size) { - init(name, size); - } + std::memcpy(buffer + state->tail, data, end); + std::memcpy(buffer, data + end, len - end); - void SM_Base_RingBuffer::init(const std::string &name, size_t size) { - data_mutex.init(name + "_data_mutex"); - create_mutex.init(name + "_create_mutex"); - std::lock_guard lock(create_mutex); + // 优化点:使用 & 代替 % + state->tail = (state->tail + len) & mask; +} - // --- 修改点 1: 确保数据区本身是 2 的幂 --- - size_t data_size_pow2 = ceilToPow2(size + 1); - size_t total_alloc_size = sizeof(SharedMemoryState) + data_size_pow2; +void SM_Base_RingBuffer::read_bytes(uint8_t *data, size_t len) { + size_t end = std::min(len, state->capacity - state->head); - bool ok; - std::ostringstream oss; - bool open = check_if_shared_memory_exists(name); + std::memcpy(data, buffer + state->head, end); + std::memcpy(data + end, buffer, len - end); - if (open) { - // 注意:打开时也要使用计算出的 total_alloc_size - oss << "【打开共享内存】" << VAR_STR_3(name, total_alloc_size, size) << std::endl; - ok = shm.open(name, total_alloc_size); - create = false; - } else { - oss << "【创建共享内存】" << VAR_STR_3(name, total_alloc_size, size) << std::endl; - ok = shm.create(name, total_alloc_size); - create = true; - } + // 优化点:使用 & 代替 % + state->head = (state->head + len) & mask; +} - if (!ok) { - std::cerr << oss.str() << "无法创建或打开共享内存!" << std::endl; - Psc::fail_fast(); - } +void SM_Base_RingBuffer::peek_bytes(uint8_t *data, size_t len) const { + size_t end = std::min(len, state->capacity - state->head); + std::memcpy(data, buffer + state->head, end); + std::memcpy(data + end, buffer, len - end); + // 不更新 state->head +} - state = reinterpret_cast(shm.data()); - uint8_t *raw = shm.data(); +bool SM_RingBuffer::write(const uint8_t *src, size_t len) { + std::lock_guard lock(data_mutex); + size_t need = HEADER_SIZE + len; - if (!open) { - // --- 修改点 2: 直接存储 2 的幂 --- - state->capacity = data_size_pow2; - state->head = 0; - state->tail = 0; - } else { - if (state->capacity == 0 || (state->capacity & mask) != 0) { - std::cerr << "致命错误:共享内存容量非法,必须为 2 的幂!" << std::endl; - Psc::fail_fast(); - } - } + // 包模式:空间不够直接返回 false,不能拆分写入 + if (free_space() < need) + return false; - // --- 修改点 3: 这里的 mask 赋值必须在获取 state 之后,无论 open 还是 create 都要执行 --- - mask = state->capacity - 1; - buffer = raw + sizeof(SharedMemoryState); + auto header = static_cast(len); + write_bytes(reinterpret_cast(&header), HEADER_SIZE); + write_bytes(src, len); + return true; +} - // 打印调试信息 - oss.str(""); // 清空 - oss << "\t实际分配容量 (2^n): " << state->capacity << std::endl; - oss << "\tMask: " << std::hex << mask << std::dec << std::endl; - std::cout << oss.str(); - } +bool SM_RingBuffer::read(uint8_t *out, size_t &out_len) { + std::lock_guard lock(data_mutex); + if (empty()) + return false; + uint32_t msg_len; + // 1. 尝试读包头 + peek_bytes(reinterpret_cast(&msg_len), HEADER_SIZE); - SM_Base_RingBuffer::SM_Base_RingBuffer() = default; - SM_Base_RingBuffer::~SM_Base_RingBuffer() { - // 尤其注意不要删除共享内存删除会导致共享内存很奇怪 - shm.close(); // 关闭共享内存 - } - std::string SM_Base_RingBuffer::state_str() { - return std::to_string(state->head) + "," + std::to_string(state->tail) + "," + std::to_string(state->capacity); - } - void SM_Base_RingBuffer::write_bytes(const uint8_t *data, size_t len) { - // 计算到缓冲区末尾的距离 - size_t end = std::min(len, state->capacity - state->tail); + // 2. 检查包体是否已全部到达(流中可能只有半个包) + if (used_space() < HEADER_SIZE + msg_len) + return false; - std::memcpy(buffer + state->tail, data, end); - std::memcpy(buffer, data + end, len - end); + // 3. 正式读取 + size_t dummy_header_len; + read_bytes(reinterpret_cast(&dummy_header_len), + HEADER_SIZE); // 移动 head 指针过 Header + read_bytes(out, msg_len); // 读取 Body - // 优化点:使用 & 代替 % - state->tail = (state->tail + len) & mask; - } + out_len = msg_len; + return true; +} - void SM_Base_RingBuffer::read_bytes(uint8_t *data, size_t len) { - size_t end = std::min(len, state->capacity - state->head); +bool SM_Stream_RingBuffer::write(const uint8_t *src, size_t len) { + if (len == 0) + return true; + std::lock_guard lock(data_mutex); - std::memcpy(data, buffer + state->head, end); - std::memcpy(data + end, buffer, len - end); + if (free_space() < len) + return false; - // 优化点:使用 & 代替 % - state->head = (state->head + len) & mask; - } + write_bytes(src, len); + return true; +} - void SM_Base_RingBuffer::peek_bytes(uint8_t *data, size_t len) const { - size_t end = std::min(len, state->capacity - state->head); - std::memcpy(data, buffer + state->head, end); - std::memcpy(data + end, buffer, len - end); - // 不更新 state->head - } +bool SM_Stream_RingBuffer::read(uint8_t *out, size_t &out_len) { + if (out_len == 0) + return true; + std::lock_guard lock(data_mutex); - bool SM_RingBuffer::write(const uint8_t *src, size_t len) { - std::lock_guard lock(data_mutex); - size_t need = HEADER_SIZE + len; + if (used_space() < out_len) { + out_len = 0; + return false; + } - // 包模式:空间不够直接返回 false,不能拆分写入 - if (free_space() < need) return false; + read_bytes(out, out_len); + return true; +} - auto header = static_cast(len); - write_bytes(reinterpret_cast(&header), HEADER_SIZE); - write_bytes(src, len); - return true; - } +// --- Best Effort 读写:尽可能操作,返回实际处理的字节数 --- - bool SM_RingBuffer::read(uint8_t *out, size_t &out_len) { - std::lock_guard lock(data_mutex); - if (empty()) return false; +size_t SM_Stream_RingBuffer::write_best_effort(const uint8_t *src, size_t len) { + if (len == 0) + return 0; + std::lock_guard lock(data_mutex); - uint32_t msg_len; - // 1. 尝试读包头 - peek_bytes(reinterpret_cast(&msg_len), HEADER_SIZE); + size_t can_write = free_space(); + size_t actual_len = std::min(len, can_write); - // 2. 检查包体是否已全部到达(流中可能只有半个包) - if (used_space() < HEADER_SIZE + msg_len) return false; + if (actual_len > 0) { + write_bytes(src, actual_len); + } + return actual_len; +} - // 3. 正式读取 - size_t dummy_header_len; - read_bytes(reinterpret_cast(&dummy_header_len), HEADER_SIZE); // 移动 head 指针过 Header - read_bytes(out, msg_len); // 读取 Body +size_t SM_Stream_RingBuffer::read_best_effort(uint8_t *out, size_t max_len) { + if (max_len == 0) + return 0; + std::lock_guard lock(data_mutex); - out_len = msg_len; - return true; - } + size_t can_read = used_space(); + size_t actual_len = std::min(max_len, can_read); - - bool SM_Stream_RingBuffer::write(const uint8_t *src, size_t len) { - if (len == 0) return true; - std::lock_guard lock(data_mutex); - - if (free_space() < len) return false; - - write_bytes(src, len); - return true; - } - - bool SM_Stream_RingBuffer::read(uint8_t *out, size_t &out_len) { - if (out_len == 0) return true; - std::lock_guard lock(data_mutex); - - if (used_space() < out_len) { - out_len = 0; - return false; - } - - read_bytes(out, out_len); - return true; - } - - // --- Best Effort 读写:尽可能操作,返回实际处理的字节数 --- - - size_t SM_Stream_RingBuffer::write_best_effort(const uint8_t *src, size_t len) { - if (len == 0) return 0; - std::lock_guard lock(data_mutex); - - size_t can_write = free_space(); - size_t actual_len = std::min(len, can_write); - - if (actual_len > 0) { - write_bytes(src, actual_len); - } - return actual_len; - } - - size_t SM_Stream_RingBuffer::read_best_effort(uint8_t *out, size_t max_len) { - if (max_len == 0) return 0; - std::lock_guard lock(data_mutex); - - size_t can_read = used_space(); - size_t actual_len = std::min(max_len, can_read); - - if (actual_len > 0) { - read_bytes(out, actual_len); - } - return actual_len; - } + if (actual_len > 0) { + read_bytes(out, actual_len); + } + return actual_len; +} } // namespace Psc @@ -245,9 +256,8 @@ namespace Psc { // size_t len; // auto ok = sm.read(buf, len); // while (ok) { -// std::cout << VAR_STR_1(len) << std::string((char*)buf, len) << std::endl; -// ok = sm.read(buf, len); -// if (++i == n) break; +// std::cout << VAR_STR_1(len) << std::string((char*)buf, len) +// << std::endl; ok = sm.read(buf, len); if (++i == n) break; // } // // std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // } diff --git a/Core/Base/SM_RingBuffer.h b/Core/Base/SM_RingBuffer.h index 816cd4d..2ad3e30 100644 --- a/Core/Base/SM_RingBuffer.h +++ b/Core/Base/SM_RingBuffer.h @@ -4,57 +4,54 @@ namespace Psc { - - - - class SM_Base_RingBuffer { - public: - struct SharedMemoryState { - alignas(64) size_t capacity; - alignas(64) size_t head; - alignas(64) size_t tail; - }; - void init(const std::string &name, size_t size); - SM_Base_RingBuffer(); - SM_Base_RingBuffer(const std::string &name, size_t alloc_size); - [[nodiscard]] bool empty() const; - [[nodiscard]] bool full() const; - ~SM_Base_RingBuffer(); - Shared_Memory shm; - std::string state_str(); - protected: - SharedMemoryState *state{}; - uint8_t *buffer{}; - size_t mask{}; - Cross_Process_Mutex data_mutex; - Cross_Process_Mutex create_mutex; - bool create = false; - [[nodiscard]] size_t used_space() const; - [[nodiscard]] size_t free_space() const; - void rollback(size_t n); - void write_bytes(const uint8_t *data, size_t len); - void read_bytes(uint8_t *data, size_t len); - void peek_bytes(uint8_t *data, size_t len) const; +class SM_Base_RingBuffer { +public: + struct SharedMemoryState { + alignas(64) size_t capacity; + alignas(64) size_t head; + alignas(64) size_t tail; }; + void init(const std::string &name, size_t size); + SM_Base_RingBuffer(); + SM_Base_RingBuffer(const std::string &name, size_t alloc_size); + [[nodiscard]] bool empty() const; + [[nodiscard]] bool full() const; + ~SM_Base_RingBuffer(); + Shared_Memory shm; + std::string state_str(); - // 包模式读取数据 - class SM_RingBuffer : public SM_Base_RingBuffer { - public: - static constexpr size_t HEADER_SIZE = sizeof(uint32_t); - bool write(const uint8_t *src, size_t len); - bool read(uint8_t *out, size_t &out_len); - }; +protected: + SharedMemoryState *state{}; + uint8_t *buffer{}; + size_t mask{}; + Cross_Process_Mutex data_mutex; + Cross_Process_Mutex create_mutex; + bool create = false; + [[nodiscard]] size_t used_space() const; + [[nodiscard]] size_t free_space() const; + void rollback(size_t n); + void write_bytes(const uint8_t *data, size_t len); + void read_bytes(uint8_t *data, size_t len); + void peek_bytes(uint8_t *data, size_t len) const; +}; - // 流模式读取环境缓冲区 - class SM_Stream_RingBuffer : public SM_Base_RingBuffer { - public: - bool write(const uint8_t *src, size_t len); - bool read(uint8_t *out, size_t &out_len); - size_t write_best_effort(const uint8_t *src, size_t len); - size_t read_best_effort(uint8_t *out, size_t max_len); - }; +// 包模式读取数据 +class SM_RingBuffer : public SM_Base_RingBuffer { +public: + static constexpr size_t HEADER_SIZE = sizeof(uint32_t); + bool write(const uint8_t *src, size_t len); + bool read(uint8_t *out, size_t &out_len); +}; -} +// 流模式读取环境缓冲区 +class SM_Stream_RingBuffer : public SM_Base_RingBuffer { +public: + bool write(const uint8_t *src, size_t len); + bool read(uint8_t *out, size_t &out_len); + size_t write_best_effort(const uint8_t *src, size_t len); + size_t read_best_effort(uint8_t *out, size_t max_len); +}; +} // namespace Psc #endif diff --git a/Core/Base/ThreadManager.h b/Core/Base/ThreadManager.h index accc7ae..6526c69 100644 --- a/Core/Base/ThreadManager.h +++ b/Core/Base/ThreadManager.h @@ -1,6 +1,6 @@ #pragma once - +#include "Core/Statistics/Frequency_Limit.h" #include #include #include @@ -9,27 +9,32 @@ #include #include #include -#include "Core/Statistics/Frequency_Limit.h" - struct Detach_Thread { - explicit Detach_Thread(const std::string& name, const std::function& running)>& func); - void start(); - std::string name; - std::thread thread; - std::atomic running = true; //控制运行 - std::atomic exit = false; + explicit Detach_Thread( + const std::string &name, + const std::function &running)> &func); + void start(); + std::string name; + std::thread thread; + std::atomic running = true; // 控制运行 + std::atomic exit = false; }; struct Detach_Thread_Manager { - Detach_Thread_Manager() = default; - void test_and_start_thread(const std::string& name, const std::function& running)>& func); - void test_and_stop_thread(const std::string& name); - void stop_all_thread(size_t timeout_milliseconds = 10000, std::set excluded_thread = {}); - Detach_Thread* get_thread(const std::thread::id thread_id); + Detach_Thread_Manager() = default; + void test_and_start_thread( + const std::string &name, + const std::function &running)> &func); + void test_and_stop_thread(const std::string &name); + void stop_all_thread(size_t timeout_milliseconds = 10000, + std::set excluded_thread = {}); + Detach_Thread *get_thread(const std::thread::id thread_id); + protected: - Frequency_Limit fl; - std::map thread_map; - void exit_thread(const std::string& name); - void start_thread(const std::string &name, const std::function &)> &f); - std::chrono::time_point exit_time; + Frequency_Limit fl; + std::map thread_map; + void exit_thread(const std::string &name); + void start_thread(const std::string &name, + const std::function &)> &f); + std::chrono::time_point exit_time; }; diff --git a/Core/Net_Adapter/Net_Adapter.cpp b/Core/Net_Adapter/Net_Adapter.cpp index 3fa1168..fdf2c36 100644 --- a/Core/Net_Adapter/Net_Adapter.cpp +++ b/Core/Net_Adapter/Net_Adapter.cpp @@ -1,6 +1,4 @@ #include "Net_Adapter.h" #include #include -namespace Psc { - -} // namespace Psc +namespace Psc {} // namespace Psc diff --git a/Core/Net_Adapter/Net_Adapter.h b/Core/Net_Adapter/Net_Adapter.h index 06f707a..123d033 100644 --- a/Core/Net_Adapter/Net_Adapter.h +++ b/Core/Net_Adapter/Net_Adapter.h @@ -6,71 +6,59 @@ #include #include namespace Psc { - struct IP_Info { - virtual ~IP_Info() = default; - std::string inet; - std::string gate; - std::optional description; - [[nodiscard]] virtual JSON to_Json() const { - JSON ret = JSON::object(); - Ret_J(inet) - Ret_J(gate) - Ret_J(description) - return ret; - } - }; +struct IP_Info { + virtual ~IP_Info() = default; + std::string inet; + std::string gate; + std::optional description; + [[nodiscard]] virtual JSON to_Json() const { + JSON ret = JSON::object(); + Ret_J(inet) Ret_J(gate) Ret_J(description) return ret; + } +}; - struct IPV4 : public IP_Info { - std::string subnet_mask; - std::optional boardcast; - [[nodiscard]] JSON to_Json() const override { - JSON ret = IP_Info::to_Json(); - Ret_J(subnet_mask) - Ret_J(boardcast) - return ret; - } - }; +struct IPV4 : public IP_Info { + std::string subnet_mask; + std::optional boardcast; + [[nodiscard]] JSON to_Json() const override { + JSON ret = IP_Info::to_Json(); + Ret_J(subnet_mask) Ret_J(boardcast) return ret; + } +}; - struct IPV6 : public IP_Info { +struct IPV6 : public IP_Info {}; - }; - - struct Net_Adapter_Info { - std::string name; - std::string mac; - std::string description; +struct Net_Adapter_Info { + std::string name; + std::string mac; + std::string description; #ifdef os_is_win - int index{}; - std::string dev_type; + int index{}; + std::string dev_type; #endif //! os_is_win - std::list ipv4s; - std::list ipv6s; - [[nodiscard]] JSON to_Json() const { - JSON ret = JSON::object(); - Ret_J(name) - Ret_J(mac) - Ret_J(description) + std::list ipv4s; + std::list ipv6s; + [[nodiscard]] JSON to_Json() const { + JSON ret = JSON::object(); + Ret_J(name) Ret_J(mac) Ret_J(description) #ifdef os_is_win - Ret_J(index) - Ret_J(dev_type) + Ret_J(index) Ret_J(dev_type) #endif auto ipv4 = JSON::array(); - for (const auto& item : ipv4s) - { - ipv4.append(item.to_Json()); - } - ret.append(JSON("ipv4_list", ipv4)); - if (!ipv6s.empty()) { - auto ipv6 = JSON::array(); - for (const auto& item : ipv6s) - { - ipv6.append(item.to_Json()); - } - ret.append(JSON("ipv6_list", ipv6)); - } - return ret; - } - }; - std::map get_net_adapter_info_map(); + for (const auto &item : ipv4s) { + ipv4.append(item.to_Json()); + } + ret.append(JSON("ipv4_list", ipv4)); + if (!ipv6s.empty()) { + auto ipv6 = JSON::array(); + for (const auto &item : ipv6s) { + ipv6.append(item.to_Json()); + } + ret.append(JSON("ipv6_list", ipv6)); + } + return ret; + } +}; +std::map get_net_adapter_info_map(); -} +} // namespace Psc diff --git a/Core/Net_Adapter/Net_Adapter_linux.cpp b/Core/Net_Adapter/Net_Adapter_linux.cpp index 7c9b82a..d4b04d9 100644 --- a/Core/Net_Adapter/Net_Adapter_linux.cpp +++ b/Core/Net_Adapter/Net_Adapter_linux.cpp @@ -1,284 +1,281 @@ #ifdef __linux__ -#include -#include -#include #include "Core/Base/global_include.h" +#include "Net_Adapter.h" #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include "Net_Adapter.h" #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include #include -#include - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace Psc { - // 获取指定 IP 地址的网关(下一跳) - // 参数 is_ipv6 为 true 则查询 IPv6 路由表,false 查询 IPv4 - std::string get_gateway_for_ip(const std::string &ip_str, bool is_ipv6 = false) { - // 创建 Netlink 套接字 - int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sock < 0) { - perror("socket"); - return "Socket creation failed"; - } +// 获取指定 IP 地址的网关(下一跳) +// 参数 is_ipv6 为 true 则查询 IPv6 路由表,false 查询 IPv4 +std::string get_gateway_for_ip(const std::string &ip_str, + bool is_ipv6 = false) { + // 创建 Netlink 套接字 + int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (sock < 0) { + perror("socket"); + return "Socket creation failed"; + } - // 绑定本地地址 - struct sockaddr_nl local; - memset(&local, 0, sizeof(local)); - local.nl_family = AF_NETLINK; - local.nl_pid = getpid(); - if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0) { - perror("bind"); + // 绑定本地地址 + struct sockaddr_nl local; + memset(&local, 0, sizeof(local)); + local.nl_family = AF_NETLINK; + local.nl_pid = getpid(); + if (bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0) { + perror("bind"); + close(sock); + return "Bind failed"; + } + + // 构造 Netlink 请求消息 + char buffer[4096]; + memset(buffer, 0, sizeof(buffer)); + struct nlmsghdr *nlh = reinterpret_cast(buffer); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nlh->nlmsg_type = RTM_GETROUTE; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = 1; + nlh->nlmsg_pid = getpid(); + + struct rtmsg *rtm = reinterpret_cast(NLMSG_DATA(nlh)); + rtm->rtm_family = is_ipv6 ? AF_INET6 : AF_INET; // 根据是否 IPv6 设置协议族 + + // 发送消息到内核 + struct sockaddr_nl kernel; + memset(&kernel, 0, sizeof(kernel)); + kernel.nl_family = AF_NETLINK; + struct iovec iov = {buffer, nlh->nlmsg_len}; + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_name = reinterpret_cast(&kernel); + msg.msg_namelen = sizeof(kernel); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + if (sendmsg(sock, &msg, 0) < 0) { + perror("sendmsg"); + close(sock); + return "sendmsg failed"; + } + + // 接收内核响应 + int len = recv(sock, buffer, sizeof(buffer), 0); + if (len < 0) { + perror("recv"); + close(sock); + return "recv failed"; + } + + // 解析响应数据,遍历每个 netlink 消息 + for (struct nlmsghdr *nh = reinterpret_cast(buffer); + NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + + if (nh->nlmsg_type == NLMSG_DONE) { + break; + } + if (nh->nlmsg_type == NLMSG_ERROR) { + std::cerr << "Netlink error" << std::endl; + close(sock); + return "Netlink error"; + } + + if (nh->nlmsg_type == RTM_NEWROUTE) { + struct rtmsg *route_entry = + reinterpret_cast(NLMSG_DATA(nh)); + // 可以选择性过滤:例如仅处理主路由表 + // if (route_entry->rtm_table != RT_TABLE_MAIN) continue; + + // 遍历路由属性 + struct rtattr *attr = RTM_RTA(route_entry); + int attr_len = RTM_PAYLOAD(nh); + for (; RTA_OK(attr, attr_len); attr = RTA_NEXT(attr, attr_len)) { + if (attr->rta_type == RTA_GATEWAY) { + // 找到网关属性,返回对应的网关地址 + if (is_ipv6) { + struct in6_addr gw6; + memcpy(&gw6, RTA_DATA(attr), sizeof(gw6)); + char gw6_str[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &gw6, gw6_str, sizeof(gw6_str)); close(sock); - return "Bind failed"; - } - - // 构造 Netlink 请求消息 - char buffer[4096]; - memset(buffer, 0, sizeof(buffer)); - struct nlmsghdr *nlh = reinterpret_cast(buffer); - nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - nlh->nlmsg_type = RTM_GETROUTE; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - nlh->nlmsg_seq = 1; - nlh->nlmsg_pid = getpid(); - - struct rtmsg *rtm = reinterpret_cast(NLMSG_DATA(nlh)); - rtm->rtm_family = is_ipv6 ? AF_INET6 : AF_INET; // 根据是否 IPv6 设置协议族 - - // 发送消息到内核 - struct sockaddr_nl kernel; - memset(&kernel, 0, sizeof(kernel)); - kernel.nl_family = AF_NETLINK; - struct iovec iov = { buffer, nlh->nlmsg_len }; - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = reinterpret_cast(&kernel); - msg.msg_namelen = sizeof(kernel); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - if (sendmsg(sock, &msg, 0) < 0) { - perror("sendmsg"); + return std::string(gw6_str); + } else { + struct in_addr gw4; + memcpy(&gw4, RTA_DATA(attr), sizeof(gw4)); + char gw4_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &gw4, gw4_str, sizeof(gw4_str)); close(sock); - return "sendmsg failed"; + return std::string(gw4_str); + } } - - // 接收内核响应 - int len = recv(sock, buffer, sizeof(buffer), 0); - if (len < 0) { - perror("recv"); - close(sock); - return "recv failed"; - } - - // 解析响应数据,遍历每个 netlink 消息 - for (struct nlmsghdr *nh = reinterpret_cast(buffer); - NLMSG_OK(nh, len); - nh = NLMSG_NEXT(nh, len)) { - - if (nh->nlmsg_type == NLMSG_DONE) { - break; - } - if (nh->nlmsg_type == NLMSG_ERROR) { - std::cerr << "Netlink error" << std::endl; - close(sock); - return "Netlink error"; - } - - if (nh->nlmsg_type == RTM_NEWROUTE) { - struct rtmsg *route_entry = reinterpret_cast(NLMSG_DATA(nh)); - // 可以选择性过滤:例如仅处理主路由表 - // if (route_entry->rtm_table != RT_TABLE_MAIN) continue; - - // 遍历路由属性 - struct rtattr *attr = RTM_RTA(route_entry); - int attr_len = RTM_PAYLOAD(nh); - for (; RTA_OK(attr, attr_len); attr = RTA_NEXT(attr, attr_len)) { - if (attr->rta_type == RTA_GATEWAY) { - // 找到网关属性,返回对应的网关地址 - if (is_ipv6) { - struct in6_addr gw6; - memcpy(&gw6, RTA_DATA(attr), sizeof(gw6)); - char gw6_str[INET6_ADDRSTRLEN]; - inet_ntop(AF_INET6, &gw6, gw6_str, sizeof(gw6_str)); - close(sock); - return std::string(gw6_str); - } else { - struct in_addr gw4; - memcpy(&gw4, RTA_DATA(attr), sizeof(gw4)); - char gw4_str[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &gw4, gw4_str, sizeof(gw4_str)); - close(sock); - return std::string(gw4_str); - } - } - } - } - } - - close(sock); - return "Gateway not found"; + } } + } - std::string hexToIp(const std::string& hex) { - auto t = hex2mem(hex); - auto ret = platform_2_big_endian((char*)t.data(), t.size()); - return - std::to_string((unsigned char)ret[0]) + "." + - std::to_string((unsigned char)ret[1]) + "." + - std::to_string((unsigned char)ret[2]) + "." + - std::to_string((unsigned char)ret[3]); - } - - std::vector parse(decltype(ifaddrs::ifa_flags) ifa_flags) { - std::vector ret; - if (ifa_flags & IFF_UP) ret.emplace_back("up"); - if (ifa_flags & IFF_BROADCAST) ret.emplace_back("broadcast"); - if (ifa_flags & IFF_LOOPBACK) ret.emplace_back("loopback"); - if (ifa_flags & IFF_POINTOPOINT) ret.emplace_back("point-to-point"); - if (ifa_flags & IFF_NOTRAILERS) ret.emplace_back("notrailers"); - if (ifa_flags & IFF_RUNNING) ret.emplace_back("running"); - if (ifa_flags & IFF_NOARP) ret.emplace_back("noarp"); - if (ifa_flags & IFF_PROMISC) ret.emplace_back("promise"); - if (ifa_flags & IFF_ALLMULTI) ret.emplace_back("multicast"); - if (ifa_flags & IFF_MASTER) ret.emplace_back("master"); - if (ifa_flags & IFF_SLAVE) ret.emplace_back("slave"); - if (ifa_flags & IFF_MULTICAST) ret.emplace_back("multicast"); - if (ifa_flags & IFF_PORTSEL) ret.emplace_back("port-sel"); - if (ifa_flags & IFF_AUTOMEDIA) ret.emplace_back("automedia"); - if (ifa_flags & IFF_DYNAMIC) ret.emplace_back("dynamic"); - return ret; - } - - std::string to_description(decltype(ifaddrs::ifa_flags) ifa_flags) { - std::vector cs = parse(ifa_flags); - std::string ret; - for (auto& c : cs) { - ret.append(c + " "); - } - return ret; - } - - std::map get_net_adapter_info_map() { - struct ifaddrs *ifap, *ifa; - char buf[INET6_ADDRSTRLEN]; - char netmask_buf[INET6_ADDRSTRLEN]; - char broadaddr_buf[INET6_ADDRSTRLEN]; - - // 获取所有网络接口的地址信息 - if (getifaddrs(&ifap) == -1) { - perror("getifaddrs"); - return {}; - } - std::map ifa_map; - // 遍历所有接口 - - for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == nullptr) continue; - if (ifa_map.find(ifa->ifa_name) == ifa_map.end()) - { - Net_Adapter_Info new_adapter; - new_adapter.name = ifa->ifa_name; - new_adapter.description = to_description(ifap->ifa_flags); - ifa_map.emplace(ifa->ifa_name, new_adapter); - } - Net_Adapter_Info& adapter = ifa_map[ifa->ifa_name]; - - // 获取 IPv4 地址 - if (ifa->ifa_addr->sa_family == AF_INET) { - IPV4 ip; - auto* sa = reinterpret_cast(ifa->ifa_addr); - inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof(buf)); - ip.inet = std::string(buf); - // 获取子网掩码 - auto* netmask = reinterpret_cast(ifa->ifa_netmask); - inet_ntop(AF_INET, &netmask->sin_addr, netmask_buf, sizeof(netmask_buf)); - ip.subnet_mask = std::string(netmask_buf); - // 获取广播地址 - auto *broadaddr = reinterpret_cast(ifa->ifa_broadaddr); - if (broadaddr) { - inet_ntop(AF_INET, &broadaddr->sin_addr, broadaddr_buf, sizeof(broadaddr_buf)); - ip.boardcast = std::string(broadaddr_buf); - } - ip.description = to_description(ifap->ifa_flags); - ip.gate = get_gateway_for_ip(ip.inet); - adapter.ipv4s.emplace_back(ip); - } - // 获取 IPv6 地址 - else if (ifa->ifa_addr->sa_family == AF_INET6) - { - IPV6 ip; - auto *sa6 = reinterpret_cast(ifa->ifa_addr); - inet_ntop(AF_INET6, &sa6->sin6_addr, buf, sizeof(buf)); - ip.inet = std::string(buf); - // ipv6 沒有 子网掩码 广播地址 - ip.description = to_description(ifap->ifa_flags); - ip.gate = get_gateway_for_ip(ip.inet, true); - adapter.ipv6s.emplace_back(ip); - } else if (ifa->ifa_addr->sa_family == AF_PACKET) - { - auto *sa_ll = reinterpret_cast(ifa->ifa_addr); - char mac_addr[18]; - // 格式化 MAC 地址 - snprintf(mac_addr, sizeof(mac_addr), - "%02x:%02x:%02x:%02x:%02x:%02x", - sa_ll->sll_addr[0], sa_ll->sll_addr[1], sa_ll->sll_addr[2], - sa_ll->sll_addr[3], sa_ll->sll_addr[4], sa_ll->sll_addr[5]); - adapter.mac = std::string(mac_addr); - // std::cout << "Interface: " << ifa->ifa_name << std::endl; - // std::cout << "MAC Address: " << mac_addr << std::endl; - } - } - freeifaddrs(ifap); - return ifa_map; - } - - - - void getGateway() { - std::ifstream file("/proc/net/route"); - std::string line; - while (std::getline(file, line)) { - std::istringstream linestream(line); - std::string iface, destination, gateway; - - linestream >> iface >> destination >> gateway; - - // 只关注默认路由(destination 是 00000000) - if (destination == "00000000") { - std::string gatewayIp = hexToIp(gateway); // 将网关的十六进制地址转换为IP地址 - std::cout << "Interface: " << iface << " Gateway: " << gatewayIp << std::endl; - } - } - } - - - - + close(sock); + return "Gateway not found"; } + +std::string hexToIp(const std::string &hex) { + auto t = hex2mem(hex); + auto ret = platform_2_big_endian((char *)t.data(), t.size()); + return std::to_string((unsigned char)ret[0]) + "." + + std::to_string((unsigned char)ret[1]) + "." + + std::to_string((unsigned char)ret[2]) + "." + + std::to_string((unsigned char)ret[3]); +} + +std::vector parse(decltype(ifaddrs::ifa_flags) ifa_flags) { + std::vector ret; + if (ifa_flags & IFF_UP) + ret.emplace_back("up"); + if (ifa_flags & IFF_BROADCAST) + ret.emplace_back("broadcast"); + if (ifa_flags & IFF_LOOPBACK) + ret.emplace_back("loopback"); + if (ifa_flags & IFF_POINTOPOINT) + ret.emplace_back("point-to-point"); + if (ifa_flags & IFF_NOTRAILERS) + ret.emplace_back("notrailers"); + if (ifa_flags & IFF_RUNNING) + ret.emplace_back("running"); + if (ifa_flags & IFF_NOARP) + ret.emplace_back("noarp"); + if (ifa_flags & IFF_PROMISC) + ret.emplace_back("promise"); + if (ifa_flags & IFF_ALLMULTI) + ret.emplace_back("multicast"); + if (ifa_flags & IFF_MASTER) + ret.emplace_back("master"); + if (ifa_flags & IFF_SLAVE) + ret.emplace_back("slave"); + if (ifa_flags & IFF_MULTICAST) + ret.emplace_back("multicast"); + if (ifa_flags & IFF_PORTSEL) + ret.emplace_back("port-sel"); + if (ifa_flags & IFF_AUTOMEDIA) + ret.emplace_back("automedia"); + if (ifa_flags & IFF_DYNAMIC) + ret.emplace_back("dynamic"); + return ret; +} + +std::string to_description(decltype(ifaddrs::ifa_flags) ifa_flags) { + std::vector cs = parse(ifa_flags); + std::string ret; + for (auto &c : cs) { + ret.append(c + " "); + } + return ret; +} + +std::map get_net_adapter_info_map() { + struct ifaddrs *ifap, *ifa; + char buf[INET6_ADDRSTRLEN]; + char netmask_buf[INET6_ADDRSTRLEN]; + char broadaddr_buf[INET6_ADDRSTRLEN]; + + // 获取所有网络接口的地址信息 + if (getifaddrs(&ifap) == -1) { + perror("getifaddrs"); + return {}; + } + std::map ifa_map; + // 遍历所有接口 + + for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == nullptr) + continue; + if (ifa_map.find(ifa->ifa_name) == ifa_map.end()) { + Net_Adapter_Info new_adapter; + new_adapter.name = ifa->ifa_name; + new_adapter.description = to_description(ifap->ifa_flags); + ifa_map.emplace(ifa->ifa_name, new_adapter); + } + Net_Adapter_Info &adapter = ifa_map[ifa->ifa_name]; + + // 获取 IPv4 地址 + if (ifa->ifa_addr->sa_family == AF_INET) { + IPV4 ip; + auto *sa = reinterpret_cast(ifa->ifa_addr); + inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof(buf)); + ip.inet = std::string(buf); + // 获取子网掩码 + auto *netmask = reinterpret_cast(ifa->ifa_netmask); + inet_ntop(AF_INET, &netmask->sin_addr, netmask_buf, sizeof(netmask_buf)); + ip.subnet_mask = std::string(netmask_buf); + // 获取广播地址 + auto *broadaddr = reinterpret_cast(ifa->ifa_broadaddr); + if (broadaddr) { + inet_ntop(AF_INET, &broadaddr->sin_addr, broadaddr_buf, + sizeof(broadaddr_buf)); + ip.boardcast = std::string(broadaddr_buf); + } + ip.description = to_description(ifap->ifa_flags); + ip.gate = get_gateway_for_ip(ip.inet); + adapter.ipv4s.emplace_back(ip); + } + // 获取 IPv6 地址 + else if (ifa->ifa_addr->sa_family == AF_INET6) { + IPV6 ip; + auto *sa6 = reinterpret_cast(ifa->ifa_addr); + inet_ntop(AF_INET6, &sa6->sin6_addr, buf, sizeof(buf)); + ip.inet = std::string(buf); + // ipv6 沒有 子网掩码 广播地址 + ip.description = to_description(ifap->ifa_flags); + ip.gate = get_gateway_for_ip(ip.inet, true); + adapter.ipv6s.emplace_back(ip); + } else if (ifa->ifa_addr->sa_family == AF_PACKET) { + auto *sa_ll = reinterpret_cast(ifa->ifa_addr); + char mac_addr[18]; + // 格式化 MAC 地址 + snprintf(mac_addr, sizeof(mac_addr), "%02x:%02x:%02x:%02x:%02x:%02x", + sa_ll->sll_addr[0], sa_ll->sll_addr[1], sa_ll->sll_addr[2], + sa_ll->sll_addr[3], sa_ll->sll_addr[4], sa_ll->sll_addr[5]); + adapter.mac = std::string(mac_addr); + // std::cout << "Interface: " << ifa->ifa_name << std::endl; + // std::cout << "MAC Address: " << mac_addr << std::endl; + } + } + freeifaddrs(ifap); + return ifa_map; +} + +void getGateway() { + std::ifstream file("/proc/net/route"); + std::string line; + while (std::getline(file, line)) { + std::istringstream linestream(line); + std::string iface, destination, gateway; + + linestream >> iface >> destination >> gateway; + + // 只关注默认路由(destination 是 00000000) + if (destination == "00000000") { + std::string gatewayIp = + hexToIp(gateway); // 将网关的十六进制地址转换为IP地址 + std::cout << "Interface: " << iface << " Gateway: " << gatewayIp + << std::endl; + } + } +} + +} // namespace Psc #endif diff --git a/Core/Serial/Serial.cpp b/Core/Serial/Serial.cpp index 4d5caef..ad9c6a5 100644 --- a/Core/Serial/Serial.cpp +++ b/Core/Serial/Serial.cpp @@ -4,299 +4,276 @@ #include #include -void serial_log(Log_Type& log_type, const std::string& MSG) { - Frequency_Limit_Multi lm; - bool ok = lm.test(std::to_string(Psc::get_error_code())); - if (!ok) return; +void serial_log(Log_Type &log_type, const std::string &MSG) { + Frequency_Limit_Multi lm; + bool ok = lm.test(std::to_string(Psc::get_error_code())); + if (!ok) + return; - std::ostringstream oss; - oss - << Psc::get_error_message() - << BaseLogger::to_log({true, spdlog::level::debug, "", log_type, MSG}) - << std::endl; - if(!Psc::serial::serial_logger) - { - std::cout << oss.str() << std::endl; - } else { - Psc::serial::serial_logger->error(" ", {}, oss.str()); - } + std::ostringstream oss; + oss << Psc::get_error_message() + << BaseLogger::to_log({true, spdlog::level::debug, "", log_type, MSG}) + << std::endl; + if (!Psc::serial::serial_logger) { + std::cout << oss.str() << std::endl; + } else { + Psc::serial::serial_logger->error(" ", {}, oss.str()); + } } namespace Psc::serial { -BaseLogger* serial_logger = nullptr; - - +BaseLogger *serial_logger = nullptr; bool Serial::open() { - fd = Psc::serial::open(serial_name); - if (fd == INVALID_HANDLE_VALUE) { - LOG_ERROR("Serial::open() 打开串口失败!"); - return false; - } - serial_info = get_serial_info(fd); - set_binary_mode(serial_info); - std::ostringstream oss; - oss << "\n属性来源:\n"; - if (buffer_byte_size == -1) { - buffer_byte_size = serial::get_buffer_byte_size(fd); - oss << "\t获取 buffer_byte_size: " << buffer_byte_size << std::endl; - } else { - serial::set_buffer_byte_size(fd, buffer_byte_size); - oss << "\t设置 buffer_byte_size: " << buffer_byte_size << std::endl; - } - if (baud_rate == -1) { - baud_rate = serial::get_baud_rate(serial_info); - oss << "\t获取 baud_rate: " << baud_rate << std::endl; - } else { - serial::set_baud_rate(serial_info, fd, baud_rate); - oss << "\t设置 baud_rate: " << baud_rate << std::endl; - } - if (dataBits == DataBits::UnknownDataBits) { - dataBits = serial::get_data_bits(serial_info); - oss << "\t获取 dataBits: " << Psc::to_string(dataBits) << std::endl; - } else { - serial::set_data_bits(serial_info, dataBits); - oss << "\t设置 dataBits: " << Psc::to_string(dataBits) << std::endl; - } - if (stopBits == StopBits::UnknownStopBits) { - stopBits = serial::get_stop_bits(serial_info); - oss << "\t获取 stopBits: " << Psc::to_string(stopBits) << std::endl; - } else { - serial::set_stop_bits(serial_info, stopBits); - oss << "\t设置 stopBits: " << Psc::to_string(stopBits) << std::endl; - } - if (parity == Parity::UnknownParity) { - parity = serial::get_parity(serial_info); - oss << "\t获取 parity: " << Psc::to_string(parity) << std::endl; - } else { - serial::set_parity(serial_info, parity); - oss << "\t设置 parity: " << Psc::to_string(parity) << std::endl; - } - if (flow_control == FlowControl::UnknownFlowControl) { - flow_control = serial::get_flow_control(serial_info); - oss << "\t获取 flow_control: " <debug("", {}, oss.str()); - return true; + set_block(fd, false); + set_serial_info(fd, serial_info); + serial_logger->debug("", {}, oss.str()); + return true; } void Serial::close() { - serial::close(fd); - fd = INVALID_HANDLE_VALUE; + serial::close(fd); + fd = INVALID_HANDLE_VALUE; } -int64_t Serial::write(const std::string& data) { - return serial::write(fd, data.c_str(), data.size()); -} - -std::string Serial::read(int64_t size) { - return read_all(fd); -} - -int Serial::get_available_bytes() { - return serial::get_available_bytes(fd); +int64_t Serial::write(const std::string &data) { + return serial::write(fd, data.c_str(), data.size()); } +std::string Serial::read(int64_t size) { return read_all(fd); } +int Serial::get_available_bytes() { return serial::get_available_bytes(fd); } std::string Serial::to_string() { - std::stringstream oss; - oss << "{" << std::endl; - oss << "\tfd:" << fd << std::endl; - oss << "\tbuffer_byte_size: " << serial::get_buffer_byte_size(fd) << std::endl; - oss << "\tbaud_rate: " << serial::get_baud_rate(serial_info) << std::endl; - oss << "\tdataBits: " << Psc::to_string(serial::get_data_bits(serial_info)) << std::endl; - oss << "\tstopBits: " << Psc::to_string(serial::get_stop_bits(serial_info)) << std::endl; - oss << "\tparity: " << Psc::to_string(serial::get_parity(serial_info)) << std::endl; - oss << "\tflow_control: " << Psc::to_string(serial::get_flow_control(serial_info)) << std::endl; - oss << "}" << std::endl; - return oss.str(); + std::stringstream oss; + oss << "{" << std::endl; + oss << "\tfd:" << fd << std::endl; + oss << "\tbuffer_byte_size: " << serial::get_buffer_byte_size(fd) + << std::endl; + oss << "\tbaud_rate: " << serial::get_baud_rate(serial_info) << std::endl; + oss << "\tdataBits: " << Psc::to_string(serial::get_data_bits(serial_info)) + << std::endl; + oss << "\tstopBits: " << Psc::to_string(serial::get_stop_bits(serial_info)) + << std::endl; + oss << "\tparity: " << Psc::to_string(serial::get_parity(serial_info)) + << std::endl; + oss << "\tflow_control: " + << Psc::to_string(serial::get_flow_control(serial_info)) << std::endl; + oss << "}" << std::endl; + return oss.str(); } -void Serial::set_serial_name(const std::string& serial_name) { - this->serial_name = serial_name; +void Serial::set_serial_name(const std::string &serial_name) { + this->serial_name = serial_name; } -std::string Serial::get_serial_name() { - return this->serial_name; -} +std::string Serial::get_serial_name() { return this->serial_name; } void Serial::set_baud_rate(Baud_Rate_Type baud_rate) { - this->baud_rate = baud_rate; - if (fd != INVALID_HANDLE_VALUE) { - serial::set_baud_rate(serial_info, fd, baud_rate); - set_serial_info(fd, serial_info); - } + this->baud_rate = baud_rate; + if (fd != INVALID_HANDLE_VALUE) { + serial::set_baud_rate(serial_info, fd, baud_rate); + set_serial_info(fd, serial_info); + } } -Baud_Rate_Type Serial::get_baud_rate() { - return baud_rate; -} +Baud_Rate_Type Serial::get_baud_rate() { return baud_rate; } void Serial::set_data_bits(DataBits data_bits) { - this->dataBits = data_bits; - if (fd != INVALID_HANDLE_VALUE) { - serial::set_data_bits(serial_info, data_bits); - set_serial_info(fd, serial_info); - } + this->dataBits = data_bits; + if (fd != INVALID_HANDLE_VALUE) { + serial::set_data_bits(serial_info, data_bits); + set_serial_info(fd, serial_info); + } } -DataBits Serial::get_data_bits() { - return dataBits; -} +DataBits Serial::get_data_bits() { return dataBits; } void Serial::set_stop_bits(StopBits stop_bits) { - this->stopBits = stop_bits; - if (fd != INVALID_HANDLE_VALUE) { - serial::set_stop_bits(serial_info, stop_bits); - set_serial_info(fd, serial_info); - } + this->stopBits = stop_bits; + if (fd != INVALID_HANDLE_VALUE) { + serial::set_stop_bits(serial_info, stop_bits); + set_serial_info(fd, serial_info); + } } -StopBits Serial::get_stop_bits() { - return stopBits; -} +StopBits Serial::get_stop_bits() { return stopBits; } void Serial::set_parity(Parity parity) { - this->parity = parity; - if (fd != INVALID_HANDLE_VALUE) { - serial::set_parity(serial_info, parity); - set_serial_info(fd, serial_info); - } + this->parity = parity; + if (fd != INVALID_HANDLE_VALUE) { + serial::set_parity(serial_info, parity); + set_serial_info(fd, serial_info); + } } -Parity Serial::get_parity() { - return parity; -} +Parity Serial::get_parity() { return parity; } void Serial::set_flow_control(FlowControl flow_control) { - this->flow_control = flow_control; - if (fd != INVALID_HANDLE_VALUE) { - serial::set_flow_control(serial_info, flow_control); - set_serial_info(fd, serial_info); - } + this->flow_control = flow_control; + if (fd != INVALID_HANDLE_VALUE) { + serial::set_flow_control(serial_info, flow_control); + set_serial_info(fd, serial_info); + } } -FlowControl Serial::get_flow_control() { - return flow_control; -} +FlowControl Serial::get_flow_control() { return flow_control; } void Serial::set_buffer_byte_size(int byte_size) { - this->buffer_byte_size = byte_size; - if (fd != INVALID_HANDLE_VALUE) { - serial::set_buffer_byte_size(fd, byte_size); - } -} - -int Serial::get_buffer_byte_size() { - return buffer_byte_size; + this->buffer_byte_size = byte_size; + if (fd != INVALID_HANDLE_VALUE) { + serial::set_buffer_byte_size(fd, byte_size); + } } +int Serial::get_buffer_byte_size() { return buffer_byte_size; } std::string read_block_all(Serial_FD fd, int64_t chunkSize) { - std::string result; - // 使用 vector 分配一个缓冲区 - std::vector buffer(static_cast(chunkSize)); - while (true) - { - int64_t bytesRead = read_data(fd, buffer.data(), chunkSize); - // std::cout << "bytesRead " << bytesRead; - if (bytesRead <= 0) - { - // 出错或者没有读取到数据时退出循环 - break; - } - // 累积读取的数据 - result.append(buffer.data(), static_cast(bytesRead)); - // 如果本次读取的数据不足 chunkSize,通常认为已经没有更多数据 - if (bytesRead <= chunkSize) - { - break; - } + std::string result; + // 使用 vector 分配一个缓冲区 + std::vector buffer(static_cast(chunkSize)); + while (true) { + int64_t bytesRead = read_data(fd, buffer.data(), chunkSize); + // std::cout << "bytesRead " << bytesRead; + if (bytesRead <= 0) { + // 出错或者没有读取到数据时退出循环 + break; } - return result; + // 累积读取的数据 + result.append(buffer.data(), static_cast(bytesRead)); + // 如果本次读取的数据不足 chunkSize,通常认为已经没有更多数据 + if (bytesRead <= chunkSize) { + break; + } + } + return result; } - std::string read_all(Serial_FD fd) { - int size = get_available_bytes(fd); - if (size == 0) return ""; - auto ret = read_block_all(fd, 1024 * 4); - return ret; + int size = get_available_bytes(fd); + if (size == 0) + return ""; + auto ret = read_block_all(fd, 1024 * 4); + return ret; } bool noblock_error() { #ifdef _WIN32 - DWORD code = GetLastError(); - return code == ERROR_IO_PENDING || code == ERROR_NO_SYSTEM_RESOURCES; + DWORD code = GetLastError(); + return code == ERROR_IO_PENDING || code == ERROR_NO_SYSTEM_RESOURCES; #elif defined(__linux__) - return errno == EAGAIN || errno == EWOULDBLOCK; + return errno == EAGAIN || errno == EWOULDBLOCK; #else - return false; + return false; #endif } -int64_t write_all(Serial_FD fd, const std::string& data, int64_t chunkSize, - int64_t milliseconds, int64_t retry_count) { - int64_t total_written = 0; - int64_t data_size = static_cast(data.size()); +int64_t write_all(Serial_FD fd, const std::string &data, int64_t chunkSize, + int64_t milliseconds, int64_t retry_count) { + int64_t total_written = 0; + int64_t data_size = static_cast(data.size()); - while (total_written < data_size) { - int64_t this_chunk = std::min(chunkSize, data_size - total_written); - int64_t cur_written = 0; - int64_t retry_left = retry_count; + while (total_written < data_size) { + int64_t this_chunk = std::min(chunkSize, data_size - total_written); + int64_t cur_written = 0; + int64_t retry_left = retry_count; - while (cur_written < this_chunk) { - int64_t to_write = this_chunk - cur_written; - int64_t written = serial::write(fd, data.data() + total_written + cur_written, to_write); - if (written < 0) { - // 写入错误,返回 -1 - LOG_ERROR(VAR_STR_2(fd, written)) - return -1; + while (cur_written < this_chunk) { + int64_t to_write = this_chunk - cur_written; + int64_t written = serial::write( + fd, data.data() + total_written + cur_written, to_write); + if (written < 0) { + // 写入错误,返回 -1 + LOG_ERROR(VAR_STR_2(fd, written)) + return -1; + } + if (written > 0) { + cur_written += written; + retry_left = retry_count; // 成功写入一次后,重置 retry + } else if (written == -1) { + if (noblock_error()) { + // 非阻塞暂时无法写入 + if (retry_count != -1) { + if (--retry_left <= 0) { + LOG_ERROR("Retry limit reached"); + return total_written; } - if (written > 0) { - cur_written += written; - retry_left = retry_count; // 成功写入一次后,重置 retry - } else if (written == -1) { - if (noblock_error()) { - // 非阻塞暂时无法写入 - if (retry_count != -1) { - if (--retry_left <= 0) { - LOG_ERROR("Retry limit reached"); - return total_written; - } - } - } else { - LOG_ERROR("write failed"); - return -1; - } - } else if (written == 0) { - // 不应该发生,write 返回 0 通常表示未写任何数据 - LOG_ERROR("write returned 0 unexpectedly"); - return -1; - } - if (cur_written == this_chunk) break; - if (milliseconds > 0) { - - std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); - } - + } + } else { + LOG_ERROR("write failed"); + return -1; } + } else if (written == 0) { + // 不应该发生,write 返回 0 通常表示未写任何数据 + LOG_ERROR("write returned 0 unexpectedly"); + return -1; + } + if (cur_written == this_chunk) + break; + if (milliseconds > 0) { - total_written += cur_written; + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); + } } - return total_written; + total_written += cur_written; + } + + return total_written; } - - -} +} // namespace Psc::serial diff --git a/Core/Serial/Serial.h b/Core/Serial/Serial.h index 69dccfc..bd07e1a 100644 --- a/Core/Serial/Serial.h +++ b/Core/Serial/Serial.h @@ -1,18 +1,18 @@ #pragma once #include -#include #include +#include #include #include +#include #include -#include - // #define USE_TERMIOS2 -//#define USE_TERMIOS +// #define USE_TERMIOS // 这个不好使 -//#define USE_SERIAL_STRUCT -#if !defined(USE_TERMIOS2) && !defined(USE_TERMIOS) && !defined(USE_SERIAL_STRUCT) +// #define USE_SERIAL_STRUCT +#if !defined(USE_TERMIOS2) && !defined(USE_TERMIOS) && \ + !defined(USE_SERIAL_STRUCT) #define USE_TERMIOS #endif #ifdef _WIN32 @@ -21,139 +21,145 @@ using Serial_Settings = DCB; using Serial_FD = HANDLE; using Baud_Rate_Type = int; #else - #include - #include - #include +#include +#include +#include #if defined(USE_TERMIOS) - #include - #include - using Serial_Settings = termios; +#include +#include +using Serial_Settings = termios; #elif defined(USE_TERMIOS2) - //#include - #include - using Serial_Settings = termios2; +// #include +#include +using Serial_Settings = termios2; #elif defined(USE_SERIAL_STRUCT) - #include - #include - using Serial_Settings = serial_struct; +#include +#include +using Serial_Settings = serial_struct; #endif - using Baud_Rate_Type = unsigned int; - using Serial_FD = int; +using Baud_Rate_Type = unsigned int; +using Serial_FD = int; #ifndef INVALID_HANDLE_VALUE - #define INVALID_HANDLE_VALUE -1 +#define INVALID_HANDLE_VALUE -1 #endif #endif #include "../system/export.h" class BaseLogger; namespace Psc::serial { - extern BaseLogger* serial_logger; - void set_buffer_byte_size(Serial_FD fd, int byte_size); - int get_buffer_byte_size(Serial_FD fd); - void set_binary_mode(Serial_Settings& serial_info); - Serial_FD open(const std::string& port_name); - void close(Serial_FD fd); - void set_block(Serial_FD fd, bool block); - Serial_Settings get_serial_info(Serial_FD fd); - void reset(Serial_Settings& serial_info); - void set_serial_info(Serial_FD fd, Serial_Settings serial_info); - int get_available_bytes(Serial_FD fd); - int get_written_bytes(Serial_FD fd); - // windows下是阻塞的 怎么设置都是阻塞的 - int64_t read_data(Serial_FD fd, char* data, int64_t maxSize); - // 非阻塞的,windows下先获取可读的字符在读取 - std::string read_all(Serial_FD fd); - std::string read_block_all(Serial_FD fd, int64_t chunkSize); - int64_t write(Serial_FD fd, const char* data, int64_t size); +extern BaseLogger *serial_logger; +void set_buffer_byte_size(Serial_FD fd, int byte_size); +int get_buffer_byte_size(Serial_FD fd); +void set_binary_mode(Serial_Settings &serial_info); +Serial_FD open(const std::string &port_name); +void close(Serial_FD fd); +void set_block(Serial_FD fd, bool block); +Serial_Settings get_serial_info(Serial_FD fd); +void reset(Serial_Settings &serial_info); +void set_serial_info(Serial_FD fd, Serial_Settings serial_info); +int get_available_bytes(Serial_FD fd); +int get_written_bytes(Serial_FD fd); +// windows下是阻塞的 怎么设置都是阻塞的 +int64_t read_data(Serial_FD fd, char *data, int64_t maxSize); +// 非阻塞的,windows下先获取可读的字符在读取 +std::string read_all(Serial_FD fd); +std::string read_block_all(Serial_FD fd, int64_t chunkSize); +int64_t write(Serial_FD fd, const char *data, int64_t size); - // milliseconds == 0 代表非阻塞 最快直接返回 - int64_t write_all(Serial_FD fd, const std::string& data, int64_t chunkSize, int64_t milliseconds, int64_t retry_count); +// milliseconds == 0 代表非阻塞 最快直接返回 +int64_t write_all(Serial_FD fd, const std::string &data, int64_t chunkSize, + int64_t milliseconds, int64_t retry_count); - inline int64_t write_all_noblock(Serial_FD fd, const std::string& data, int64_t chunkSize) { - return write_all(fd, data, chunkSize, 0, 0); - } - inline int64_t write_all_block(Serial_FD fd, const std::string& data, int64_t chunkSize) { - return write_all(fd, data, chunkSize, 1, -1); - } - void set_baud_rate(Serial_Settings& serial_info, Serial_FD fd, Baud_Rate_Type baud); - Baud_Rate_Type get_baud_rate(Serial_Settings& serial_info); - std::string get_serial_info_str(std::string serial_name); +inline int64_t write_all_noblock(Serial_FD fd, const std::string &data, + int64_t chunkSize) { + return write_all(fd, data, chunkSize, 0, 0); +} +inline int64_t write_all_block(Serial_FD fd, const std::string &data, + int64_t chunkSize) { + return write_all(fd, data, chunkSize, 1, -1); +} +void set_baud_rate(Serial_Settings &serial_info, Serial_FD fd, + Baud_Rate_Type baud); +Baud_Rate_Type get_baud_rate(Serial_Settings &serial_info); +std::string get_serial_info_str(std::string serial_name); - enum class DataBits { - Data5 = 5, - Data6 = 6, - Data7 = 7, - Data8 = 8, - UnknownDataBits = -1 - }; +enum class DataBits { + Data5 = 5, + Data6 = 6, + Data7 = 7, + Data8 = 8, + UnknownDataBits = -1 +}; - void set_data_bits(Serial_Settings& serial_info, DataBits data_bits); - DataBits get_data_bits(Serial_Settings& serial_info); +void set_data_bits(Serial_Settings &serial_info, DataBits data_bits); +DataBits get_data_bits(Serial_Settings &serial_info); - enum class StopBits { - OneStop = 1, - OneAndHalfStop = 3, - TwoStop = 2, - UnknownStopBits = -1 - }; +enum class StopBits { + OneStop = 1, + OneAndHalfStop = 3, + TwoStop = 2, + UnknownStopBits = -1 +}; - void set_stop_bits(Serial_Settings& serial_info, StopBits stop_bits); - StopBits get_stop_bits(Serial_Settings& serial_info); +void set_stop_bits(Serial_Settings &serial_info, StopBits stop_bits); +StopBits get_stop_bits(Serial_Settings &serial_info); - enum class Parity { - NoParity = 0, - EvenParity = 2, - OddParity = 3, - SpaceParity = 4, - MarkParity = 5, - UnknownParity = -1 - }; +enum class Parity { + NoParity = 0, + EvenParity = 2, + OddParity = 3, + SpaceParity = 4, + MarkParity = 5, + UnknownParity = -1 +}; - void set_parity(Serial_Settings& serial_info, Parity parity); - Parity get_parity(Serial_Settings& serial_info); +void set_parity(Serial_Settings &serial_info, Parity parity); +Parity get_parity(Serial_Settings &serial_info); - enum class FlowControl { - NoFlowControl, - HardwareControl, - SoftwareControl, - UnknownFlowControl = -1 - }; +enum class FlowControl { + NoFlowControl, + HardwareControl, + SoftwareControl, + UnknownFlowControl = -1 +}; - void set_flow_control(Serial_Settings& serial_info, FlowControl flow_control); - FlowControl get_flow_control(Serial_Settings& serial_info); - class Serial { - public: - bool open(); - void close(); - int64_t write(const std::string& data); - std::string read(int64_t size = -1); - int get_available_bytes(); - protected: - Baud_Rate_Type baud_rate = -1; - DataBits dataBits = DataBits::UnknownDataBits; - StopBits stopBits = StopBits::UnknownStopBits; - Parity parity = Parity::UnknownParity; - FlowControl flow_control = FlowControl::UnknownFlowControl; - Serial_FD fd = INVALID_HANDLE_VALUE; - Serial_Settings serial_info{}; - std::string serial_name; - int buffer_byte_size = -1; - public: - std::string to_string(); - void set_serial_name(const std::string& serial_name); - std::string get_serial_name(); - void set_baud_rate(Baud_Rate_Type baud_rate); - Baud_Rate_Type get_baud_rate(); - void set_data_bits(DataBits data_bits); - DataBits get_data_bits(); - void set_stop_bits(StopBits stop_bits); - StopBits get_stop_bits(); - void set_parity(Parity parity); - Parity get_parity(); - void set_flow_control(FlowControl flow_control); - FlowControl get_flow_control(); - void set_buffer_byte_size(int byte_size); - int get_buffer_byte_size(); - }; +void set_flow_control(Serial_Settings &serial_info, FlowControl flow_control); +FlowControl get_flow_control(Serial_Settings &serial_info); +class Serial { +public: + bool open(); + void close(); + int64_t write(const std::string &data); + std::string read(int64_t size = -1); + int get_available_bytes(); + +protected: + Baud_Rate_Type baud_rate = -1; + DataBits dataBits = DataBits::UnknownDataBits; + StopBits stopBits = StopBits::UnknownStopBits; + Parity parity = Parity::UnknownParity; + FlowControl flow_control = FlowControl::UnknownFlowControl; + Serial_FD fd = INVALID_HANDLE_VALUE; + Serial_Settings serial_info{}; + std::string serial_name; + int buffer_byte_size = -1; + +public: + std::string to_string(); + void set_serial_name(const std::string &serial_name); + std::string get_serial_name(); + void set_baud_rate(Baud_Rate_Type baud_rate); + Baud_Rate_Type get_baud_rate(); + void set_data_bits(DataBits data_bits); + DataBits get_data_bits(); + void set_stop_bits(StopBits stop_bits); + StopBits get_stop_bits(); + void set_parity(Parity parity); + Parity get_parity(); + void set_flow_control(FlowControl flow_control); + FlowControl get_flow_control(); + void set_buffer_byte_size(int byte_size); + int get_buffer_byte_size(); +}; } \ No newline at end of file diff --git a/Core/Serial/Serial_Coro.h b/Core/Serial/Serial_Coro.h index 8634b8a..14833b4 100644 --- a/Core/Serial/Serial_Coro.h +++ b/Core/Serial/Serial_Coro.h @@ -15,152 +15,161 @@ namespace Psc::serial { class Serial_Coro : public Serial { public: - bool open() - { - if (port_ && port_->is_open()) { - return true; - } - - port_ = std::make_unique(io_context_); - asio::error_code ec; - port_->open(normalize_port_name(serial_name), ec); - if (ec) { - return false; - } - - apply_options(ec); - if (ec) { - close(); - return false; - } - - serial::set_block(port_->native_handle(), false); - - return true; + bool open() { + if (port_ && port_->is_open()) { + return true; } - void close() - { - if (!port_) { - return; - } - - asio::error_code ec; - port_->cancel(ec); - port_->close(ec); - port_.reset(); - io_context_.restart(); + port_ = std::make_unique(io_context_); + asio::error_code ec; + port_->open(normalize_port_name(serial_name), ec); + if (ec) { + return false; } - [[nodiscard]] concurrencpp::result tick_coro() - { - io_context_.poll(); - co_return; + apply_options(ec); + if (ec) { + close(); + return false; } - [[nodiscard]] concurrencpp::result read_coro(std::size_t max_size = 16 * 1024) - { - co_await tick_coro(); - if (!port_ || !port_->is_open()) { - co_return ""; - } + serial::set_block(port_->native_handle(), false); - auto available = serial::get_available_bytes(port_->native_handle()); - if (available <= 0) { - co_return ""; - } + return true; + } - auto data = serial::read_all(port_->native_handle()); - if (data.size() > max_size) { - data.resize(max_size); - } - co_return data; + void close() { + if (!port_) { + return; } - [[nodiscard]] concurrencpp::result write_coro(std::string data) - { - co_await tick_coro(); - if (!port_ || !port_->is_open() || data.empty()) { - co_return 0; - } + asio::error_code ec; + port_->cancel(ec); + port_->close(ec); + port_.reset(); + io_context_.restart(); + } - asio::error_code ec; - auto size = asio::write(*port_, asio::buffer(data), ec); - if (ec) { - co_return 0; - } + [[nodiscard]] concurrencpp::result tick_coro() { + io_context_.poll(); + co_return; + } - co_return size; + [[nodiscard]] concurrencpp::result + read_coro(std::size_t max_size = 16 * 1024) { + co_await tick_coro(); + if (!port_ || !port_->is_open()) { + co_return ""; } - std::string read(int64_t size = -1) - { - auto max_size = size > 0 ? static_cast(size) : static_cast(16 * 1024); - return (read_coro(max_size)).get(); + auto available = serial::get_available_bytes(port_->native_handle()); + if (available <= 0) { + co_return ""; } - int64_t write(const std::string& data) - { - return static_cast(write_coro(data).get()); + auto data = serial::read_all(port_->native_handle()); + if (data.size() > max_size) { + data.resize(max_size); + } + co_return data; + } + + [[nodiscard]] concurrencpp::result write_coro(std::string data) { + co_await tick_coro(); + if (!port_ || !port_->is_open() || data.empty()) { + co_return 0; } - int get_available_bytes() - { - if (!port_ || !port_->is_open()) { - return 0; - } - return serial::get_available_bytes(port_->native_handle()); + asio::error_code ec; + auto size = asio::write(*port_, asio::buffer(data), ec); + if (ec) { + co_return 0; } + co_return size; + } + + std::string read(int64_t size = -1) { + auto max_size = size > 0 ? static_cast(size) + : static_cast(16 * 1024); + return (read_coro(max_size)).get(); + } + + int64_t write(const std::string &data) { + return static_cast(write_coro(data).get()); + } + + int get_available_bytes() { + if (!port_ || !port_->is_open()) { + return 0; + } + return serial::get_available_bytes(port_->native_handle()); + } + private: - static std::string normalize_port_name(std::string port_name) - { + static std::string normalize_port_name(std::string port_name) { #ifdef _WIN32 - if (port_name.rfind("\\\\.\\", 0) != 0) { - port_name = "\\\\.\\" + port_name; - } + if (port_name.rfind("\\\\.\\", 0) != 0) { + port_name = "\\\\.\\" + port_name; + } #endif - return port_name; + return port_name; + } + + void apply_options(asio::error_code &ec) { + if (baud_rate != static_cast(-1)) { + port_->set_option(asio::serial_port_base::baud_rate( + static_cast(baud_rate)), + ec); + if (ec) + return; } - void apply_options(asio::error_code& ec) - { - if (baud_rate != static_cast(-1)) { - port_->set_option(asio::serial_port_base::baud_rate(static_cast(baud_rate)), ec); - if (ec) return; - } - - if (dataBits != DataBits::UnknownDataBits) { - port_->set_option(asio::serial_port_base::character_size(static_cast(dataBits)), ec); - if (ec) return; - } - - if (parity != Parity::UnknownParity) { - asio::serial_port_base::parity::type value = asio::serial_port_base::parity::none; - if (parity == Parity::EvenParity) value = asio::serial_port_base::parity::even; - if (parity == Parity::OddParity) value = asio::serial_port_base::parity::odd; - port_->set_option(asio::serial_port_base::parity(value), ec); - if (ec) return; - } - - if (stopBits != StopBits::UnknownStopBits) { - asio::serial_port_base::stop_bits::type value = asio::serial_port_base::stop_bits::one; - if (stopBits == StopBits::OneAndHalfStop) value = asio::serial_port_base::stop_bits::onepointfive; - if (stopBits == StopBits::TwoStop) value = asio::serial_port_base::stop_bits::two; - port_->set_option(asio::serial_port_base::stop_bits(value), ec); - if (ec) return; - } - - if (flow_control != FlowControl::UnknownFlowControl) { - asio::serial_port_base::flow_control::type value = asio::serial_port_base::flow_control::none; - if (flow_control == FlowControl::HardwareControl) value = asio::serial_port_base::flow_control::hardware; - if (flow_control == FlowControl::SoftwareControl) value = asio::serial_port_base::flow_control::software; - port_->set_option(asio::serial_port_base::flow_control(value), ec); - } + if (dataBits != DataBits::UnknownDataBits) { + port_->set_option(asio::serial_port_base::character_size( + static_cast(dataBits)), + ec); + if (ec) + return; } - asio::io_context io_context_; - std::unique_ptr port_; + if (parity != Parity::UnknownParity) { + asio::serial_port_base::parity::type value = + asio::serial_port_base::parity::none; + if (parity == Parity::EvenParity) + value = asio::serial_port_base::parity::even; + if (parity == Parity::OddParity) + value = asio::serial_port_base::parity::odd; + port_->set_option(asio::serial_port_base::parity(value), ec); + if (ec) + return; + } + + if (stopBits != StopBits::UnknownStopBits) { + asio::serial_port_base::stop_bits::type value = + asio::serial_port_base::stop_bits::one; + if (stopBits == StopBits::OneAndHalfStop) + value = asio::serial_port_base::stop_bits::onepointfive; + if (stopBits == StopBits::TwoStop) + value = asio::serial_port_base::stop_bits::two; + port_->set_option(asio::serial_port_base::stop_bits(value), ec); + if (ec) + return; + } + + if (flow_control != FlowControl::UnknownFlowControl) { + asio::serial_port_base::flow_control::type value = + asio::serial_port_base::flow_control::none; + if (flow_control == FlowControl::HardwareControl) + value = asio::serial_port_base::flow_control::hardware; + if (flow_control == FlowControl::SoftwareControl) + value = asio::serial_port_base::flow_control::software; + port_->set_option(asio::serial_port_base::flow_control(value), ec); + } + } + + asio::io_context io_context_; + std::unique_ptr port_; }; } // namespace Psc::serial diff --git a/Core/Serial/Serial_p.h b/Core/Serial/Serial_p.h index 83157dc..c45e78c 100644 --- a/Core/Serial/Serial_p.h +++ b/Core/Serial/Serial_p.h @@ -3,11 +3,8 @@ #include "../../Core/spdlog/export.h" #include "Serial.h" +void serial_log(Log_Type &log_type, const std::string &MSG); -void serial_log(Log_Type& log_type, const std::string& MSG); - - -#define LOG_ERROR(MSG) static Log_Type log_type({}, {{"POS", LOG_POS}});\ -serial_log(log_type, MSG); - - +#define LOG_ERROR(MSG) \ + static Log_Type log_type({}, {{"POS", LOG_POS}}); \ + serial_log(log_type, MSG); diff --git a/Core/Serial/Serial_win.cpp b/Core/Serial/Serial_win.cpp index 1a0d777..4d75463 100644 --- a/Core/Serial/Serial_win.cpp +++ b/Core/Serial/Serial_win.cpp @@ -3,196 +3,191 @@ #include "Serial_p.h" namespace Psc::serial { +void reset(Serial_Settings &serial_info) { + // 清空整个结构体 + ZeroMemory(&serial_info, sizeof(DCB)); + serial_info.DCBlength = sizeof(DCB); -void reset(Serial_Settings& serial_info) { - // 清空整个结构体 - ZeroMemory(&serial_info, sizeof(DCB)); - serial_info.DCBlength = sizeof(DCB); - - // 设置默认参数(你可以根据需要修改) - serial_info.BaudRate = CBR_9600; // 默认波特率 - serial_info.ByteSize = 8; // 8位数据位 - serial_info.Parity = NOPARITY; // 无校验 - serial_info.StopBits = ONESTOPBIT; // 1位停止位 - serial_info.fBinary = TRUE; // 必须设为 TRUE - serial_info.fDtrControl = DTR_CONTROL_ENABLE; - serial_info.fRtsControl = RTS_CONTROL_ENABLE; + // 设置默认参数(你可以根据需要修改) + serial_info.BaudRate = CBR_9600; // 默认波特率 + serial_info.ByteSize = 8; // 8位数据位 + serial_info.Parity = NOPARITY; // 无校验 + serial_info.StopBits = ONESTOPBIT; // 1位停止位 + serial_info.fBinary = TRUE; // 必须设为 TRUE + serial_info.fDtrControl = DTR_CONTROL_ENABLE; + serial_info.fRtsControl = RTS_CONTROL_ENABLE; } void set_buffer_byte_size(HANDLE fd, int byte_size) { - if (fd == INVALID_HANDLE_VALUE) { - LOG_ERROR(VAR_STR_2(fd, byte_size) + "Invalid serial handle!") - } - // 设置输入缓冲区和输出缓冲区的大小 - if (!SetupComm(fd, byte_size, byte_size)) { - LOG_ERROR(VAR_STR_2(fd, byte_size) + "Failed to set buffer size!") - } - // 清空缓冲区,防止遗留数据干扰 - if (!PurgeComm(fd, PURGE_RXCLEAR | PURGE_TXCLEAR)) { - LOG_ERROR(VAR_STR_2(fd, byte_size) + "Failed to purge buffers!") - } + if (fd == INVALID_HANDLE_VALUE) { + LOG_ERROR(VAR_STR_2(fd, byte_size) + "Invalid serial handle!") + } + // 设置输入缓冲区和输出缓冲区的大小 + if (!SetupComm(fd, byte_size, byte_size)) { + LOG_ERROR(VAR_STR_2(fd, byte_size) + "Failed to set buffer size!") + } + // 清空缓冲区,防止遗留数据干扰 + if (!PurgeComm(fd, PURGE_RXCLEAR | PURGE_TXCLEAR)) { + LOG_ERROR(VAR_STR_2(fd, byte_size) + "Failed to purge buffers!") + } } - int get_buffer_byte_size(HANDLE fd) { - COMMPROP commProp = {0}; - if (GetCommProperties(fd, &commProp)) { - return commProp.dwCurrentRxQueue; // 或者返回 commProp.dwCurrentTxQueue - } else { - LOG_ERROR(VAR_STR_1(fd) + "Failed to get serial port properties.") - } - return 0; + COMMPROP commProp = {0}; + if (GetCommProperties(fd, &commProp)) { + return commProp.dwCurrentRxQueue; // 或者返回 commProp.dwCurrentTxQueue + } else { + LOG_ERROR(VAR_STR_1(fd) + "Failed to get serial port properties.") + } + return 0; } -void set_binary_mode(Serial_Settings& serial_info) { - //windows下默认就是 +void set_binary_mode(Serial_Settings &serial_info) { + // windows下默认就是 } -HANDLE open(const std::string& port_name) { - HANDLE hSerial = CreateFile(("\\\\.\\" + port_name).c_str(), - GENERIC_READ | GENERIC_WRITE, - 0, // No sharing - NULL, // Default security attributes - OPEN_EXISTING, // Open the existing port - 0, // 0 : No overlapped I/O FILE_FLAG_OVERLAPPED是异步 - NULL); // No template file - if (hSerial == INVALID_HANDLE_VALUE) { - LOG_ERROR(VAR_STR_1(port_name)) - Psc::fail_fast(); - return INVALID_HANDLE_VALUE; - } +HANDLE open(const std::string &port_name) { + HANDLE hSerial = + CreateFile(("\\\\.\\" + port_name).c_str(), GENERIC_READ | GENERIC_WRITE, + 0, // No sharing + NULL, // Default security attributes + OPEN_EXISTING, // Open the existing port + 0, // 0 : No overlapped I/O FILE_FLAG_OVERLAPPED是异步 + NULL); // No template file + if (hSerial == INVALID_HANDLE_VALUE) { + LOG_ERROR(VAR_STR_1(port_name)) + Psc::fail_fast(); + return INVALID_HANDLE_VALUE; + } - return hSerial; + return hSerial; } -//typedef struct _COMMTIMEOUTS { -// DWORD ReadIntervalTimeout; // 读间隔超时 -// DWORD ReadTotalTimeoutMultiplier; // 读时间系数 -// DWORD ReadTotalTimeoutConstant; // 读时间常量 -// DWORD WriteTotalTimeoutMultiplier; // 写时间系数 -// DWORD WriteTotalTimeoutConstant; // 写时间常量 -//} COMMTIMEOUTS,*LPCOMMTIMEOUTS; -// 有两种超时:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延,总超时是指读写操作总共花费的最大时间。 -// 写操作只支持总超时,而读操作两种超时均支持。 -// 用COMMTIMEOUTS结构可以规定读/写操作的超时,该结构的定义为: COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是: -// 总超时=时间系数×要求读/写的字符数 + 时间常量//  -// 例如,如果要读入10个字符,那么读操作的总超时的计算公式为: -// 读总超时=ReadTotalTimeoutMultiplier×10 + ReadTotalTimeoutConstant -// 如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时,如果 ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都为0, -// 则不使用读总超时。 -// 如果读间隔超时被设置成MAXDWORD并且两个读总超时为0,那么在读一次输入缓冲区中的内容后读操作就立即完成,而不管是否读入了要求的字符。 -// 在用重叠方式读写串行口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。 +// typedef struct _COMMTIMEOUTS { +// DWORD ReadIntervalTimeout; // 读间隔超时 +// DWORD ReadTotalTimeoutMultiplier; // 读时间系数 +// DWORD ReadTotalTimeoutConstant; // 读时间常量 +// DWORD WriteTotalTimeoutMultiplier; // 写时间系数 +// DWORD WriteTotalTimeoutConstant; // 写时间常量 +// } COMMTIMEOUTS,*LPCOMMTIMEOUTS; +// 有两种超时:间隔超时和总超时。间隔超时是指在接收时两个字符之间的最大时延,总超时是指读写操作总共花费的最大时间。 +// 写操作只支持总超时,而读操作两种超时均支持。 +// 用COMMTIMEOUTS结构可以规定读/写操作的超时,该结构的定义为: +// COMMTIMEOUTS结构的成员都以毫秒为单位。总超时的计算公式是: +// 总超时=时间系数×要求读/写的字符数 + 时间常量//  +// 例如,如果要读入10个字符,那么读操作的总超时的计算公式为: +// 读总超时=ReadTotalTimeoutMultiplier×10 + ReadTotalTimeoutConstant +// 如果所有写超时参数均为0,那么就不使用写超时。如果ReadIntervalTimeout为0,那么就不使用读间隔超时,如果 +// ReadTotalTimeoutMultiplier和ReadTotalTimeoutConstant都为0, +// 则不使用读总超时。 +// 如果读间隔超时被设置成MAXDWORD并且两个读总超时为0,那么在读一次输入缓冲区中的内容后读操作就立即完成,而不管是否读入了要求的字符。 +// 在用重叠方式读写串行口时,虽然ReadFile和WriteFile在完成操作以前就可能返回,但超时仍然是起作用的。在这种情况下,超时规定的是操作的完成时间,而不是ReadFile和WriteFile的返回时间。 void set_block(HANDLE fd, bool block) { - // 获取当前串口的超时设置 - COMMTIMEOUTS timeouts = {0}; - if (!GetCommTimeouts(fd, &timeouts)) { - LOG_ERROR(VAR_STR_2(fd, block)) - return; - } - // 根据 block 参数设置不同的超时行为 - if (block) { - // 阻塞模式:没有超时 - timeouts.ReadIntervalTimeout = 0; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.ReadTotalTimeoutMultiplier = 0; - timeouts.WriteTotalTimeoutConstant = 0; - timeouts.WriteTotalTimeoutMultiplier = 0; - } else { - // 非阻塞模式:设置适当的超时(例如 50 毫秒) - // timeouts.ReadIntervalTimeout = 50; - // timeouts.ReadTotalTimeoutConstant = 50; - // timeouts.ReadTotalTimeoutMultiplier = 10; - timeouts.WriteTotalTimeoutConstant = 50; - timeouts.WriteTotalTimeoutMultiplier = 10; - - - timeouts.ReadIntervalTimeout = MAXDWORD; - timeouts.ReadTotalTimeoutConstant = 0; - timeouts.ReadTotalTimeoutMultiplier = 0; - - } - // 设置新的超时参数 - if (!SetCommTimeouts(fd, &timeouts)) { - LOG_ERROR("") - } - - + // 获取当前串口的超时设置 + COMMTIMEOUTS timeouts = {0}; + if (!GetCommTimeouts(fd, &timeouts)) { + LOG_ERROR(VAR_STR_2(fd, block)) + return; + } + // 根据 block 参数设置不同的超时行为 + if (block) { + // 阻塞模式:没有超时 + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + } else { + // 非阻塞模式:设置适当的超时(例如 50 毫秒) + // timeouts.ReadIntervalTimeout = 50; + // timeouts.ReadTotalTimeoutConstant = 50; + // timeouts.ReadTotalTimeoutMultiplier = 10; + timeouts.WriteTotalTimeoutConstant = 50; + timeouts.WriteTotalTimeoutMultiplier = 10; + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + } + // 设置新的超时参数 + if (!SetCommTimeouts(fd, &timeouts)) { + LOG_ERROR("") + } } void close(Serial_FD fd) { - if (fd != INVALID_HANDLE_VALUE) { - if (CloseHandle(fd)) { - if (serial_logger) serial_logger->debug("", {}, VAR_STR_1(fd) + " Serial port closed successfully."); - } else { - LOG_ERROR(VAR_STR_1(fd) + " Failed to close the serial port.") - } + if (fd != INVALID_HANDLE_VALUE) { + if (CloseHandle(fd)) { + if (serial_logger) + serial_logger->debug( + "", {}, VAR_STR_1(fd) + " Serial port closed successfully."); } else { - LOG_ERROR(VAR_STR_1(fd)) + LOG_ERROR(VAR_STR_1(fd) + " Failed to close the serial port.") } + } else { + LOG_ERROR(VAR_STR_1(fd)) + } } - DCB get_serial_info(HANDLE fd) { - DCB dcbSerialParams = {0}; // 初始化 DCB 结构 - // 获取串口的当前状态 - if (!GetCommState(fd, &dcbSerialParams)) { - LOG_ERROR(VAR_STR_1(fd)) - // 如果获取失败,可以返回一个默认的 DCB 结构(全为零) - return dcbSerialParams; - } - // 成功获取配置后返回 DCB 结构 + DCB dcbSerialParams = {0}; // 初始化 DCB 结构 + // 获取串口的当前状态 + if (!GetCommState(fd, &dcbSerialParams)) { + LOG_ERROR(VAR_STR_1(fd)) + // 如果获取失败,可以返回一个默认的 DCB 结构(全为零) return dcbSerialParams; + } + // 成功获取配置后返回 DCB 结构 + return dcbSerialParams; } void set_serial_info(HANDLE fd, DCB serial_info) { - // 设置串口配置 - if (!SetCommState(fd, &serial_info)) { - // 如果设置失败,输出错误信息 - LOG_ERROR(VAR_STR_1(fd)) - } + // 设置串口配置 + if (!SetCommState(fd, &serial_info)) { + // 如果设置失败,输出错误信息 + LOG_ERROR(VAR_STR_1(fd)) + } } - int get_written_bytes(Serial_FD fd) { - COMSTAT comStat; - DWORD dwErrors; + COMSTAT comStat; + DWORD dwErrors; - // 获取串口通信状态 - if (!ClearCommError(fd, &dwErrors, &comStat)) { - fprintf(stderr, "ClearCommError failed: %ld\n", GetLastError()); - return -1; - } - // 返回发送缓冲区中的字节数 - return comStat.cbOutQue; + // 获取串口通信状态 + if (!ClearCommError(fd, &dwErrors, &comStat)) { + fprintf(stderr, "ClearCommError failed: %ld\n", GetLastError()); + return -1; + } + // 返回发送缓冲区中的字节数 + return comStat.cbOutQue; } int get_available_bytes(HANDLE fd) { - COMSTAT comStat; - DWORD dwErrors; - // 使用 ClearCommError 获取串口状态和接收队列中的字节数 - if (!ClearCommError(fd, &dwErrors, &comStat)) { - LOG_ERROR(VAR_STR_1(fd)) - return -1; // 出现错误时返回 -1 - } - // 返回接收队列中的字节数 - return comStat.cbInQue; + COMSTAT comStat; + DWORD dwErrors; + // 使用 ClearCommError 获取串口状态和接收队列中的字节数 + if (!ClearCommError(fd, &dwErrors, &comStat)) { + LOG_ERROR(VAR_STR_1(fd)) + return -1; // 出现错误时返回 -1 + } + // 返回接收队列中的字节数 + return comStat.cbInQue; } - -int64_t read_data(HANDLE fd, char* data, int64_t maxSize) { - DWORD bytesRead = 0; - if (!ReadFile(fd, data, maxSize, &bytesRead, NULL)) { - return -1; - } - return bytesRead; +int64_t read_data(HANDLE fd, char *data, int64_t maxSize) { + DWORD bytesRead = 0; + if (!ReadFile(fd, data, maxSize, &bytesRead, NULL)) { + return -1; + } + return bytesRead; } // int64_t read_data(Serial_FD fd, char* data, int64_t maxSize) { // OVERLAPPED overlapped = {}; // DWORD bytesRead = 0; -// if (ReadFile(fd, data, maxSize, &bytesRead, &overlapped) || GetLastError() == ERROR_IO_PENDING) { +// if (ReadFile(fd, data, maxSize, &bytesRead, &overlapped) || +// GetLastError() == ERROR_IO_PENDING) { // if (GetOverlappedResult(fd, &overlapped, &bytesRead, TRUE)) { // return bytesRead; // } @@ -200,141 +195,144 @@ int64_t read_data(HANDLE fd, char* data, int64_t maxSize) { // return 0; // 如果没有数据可以读取,直接返回 // } +int64_t write(HANDLE fd, const char *data, int64_t maxSize, + bool nonBlocking = false) { + DWORD bytesWritten = 0; + OVERLAPPED overlapped = {0}; -int64_t write(HANDLE fd, const char* data, int64_t maxSize, bool nonBlocking = false) { - DWORD bytesWritten = 0; - OVERLAPPED overlapped = {0}; - - if (nonBlocking) { - overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); - if (!overlapped.hEvent) { - std::cerr << "创建事件失败" << std::endl; - return -1; - } + if (nonBlocking) { + overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (!overlapped.hEvent) { + std::cerr << "创建事件失败" << std::endl; + return -1; } + } - BOOL success = WriteFile( - fd, - data, - static_cast(maxSize), - &bytesWritten, - nonBlocking ? &overlapped : nullptr - ); + BOOL success = WriteFile(fd, data, static_cast(maxSize), &bytesWritten, + nonBlocking ? &overlapped : nullptr); - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_IO_PENDING) { - if (nonBlocking) { - CloseHandle(overlapped.hEvent); - return 0; // 非阻塞模式下返回0表示操作挂起 - } - return -1; - } else if (error == ERROR_TIMEOUT) { - CloseHandle(overlapped.hEvent); - return 0; - } else { - CloseHandle(overlapped.hEvent); - std::cerr << "写入错误, 错误代码: " << error << std::endl; - return -1; - } - } - - if (nonBlocking) { + if (!success) { + DWORD error = GetLastError(); + if (error == ERROR_IO_PENDING) { + if (nonBlocking) { CloseHandle(overlapped.hEvent); + return 0; // 非阻塞模式下返回0表示操作挂起 + } + return -1; + } else if (error == ERROR_TIMEOUT) { + CloseHandle(overlapped.hEvent); + return 0; + } else { + CloseHandle(overlapped.hEvent); + std::cerr << "写入错误, 错误代码: " << error << std::endl; + return -1; } + } - return bytesWritten; + if (nonBlocking) { + CloseHandle(overlapped.hEvent); + } + + return bytesWritten; } -int64_t write(HANDLE fd, const char* data, int64_t size) { - DWORD written; - BOOL success = WriteFile( - fd, - data, - static_cast(size), - &written, - nullptr - ); - if (!success) - { - LOG_ERROR(""); - return -1; - } - if (written != size) - { - LOG_ERROR(""); - } - return written; +int64_t write(HANDLE fd, const char *data, int64_t size) { + DWORD written; + BOOL success = + WriteFile(fd, data, static_cast(size), &written, nullptr); + if (!success) { + LOG_ERROR(""); + return -1; + } + if (written != size) { + LOG_ERROR(""); + } + return written; } - - - -void set_baud_rate(DCB& serial_info, Serial_FD fd, int baud) { - // 设置串口波特率 - serial_info.BaudRate = baud; +void set_baud_rate(DCB &serial_info, Serial_FD fd, int baud) { + // 设置串口波特率 + serial_info.BaudRate = baud; } -int get_baud_rate(DCB& serial_info) { - return serial_info.BaudRate; +int get_baud_rate(DCB &serial_info) { return serial_info.BaudRate; } + +void set_data_bits(DCB &serial_info, DataBits data_bits) { + serial_info.ByteSize = static_cast(data_bits); } -void set_data_bits(DCB& serial_info, DataBits data_bits) { - serial_info.ByteSize = static_cast(data_bits); +DataBits get_data_bits(DCB &serial_info) { + return static_cast(serial_info.ByteSize); } -DataBits get_data_bits(DCB& serial_info) { - return static_cast(serial_info.ByteSize); +void set_stop_bits(DCB &serial_info, StopBits stop_bits) { + switch (stop_bits) { + case StopBits::OneStop: + serial_info.StopBits = ONESTOPBIT; + break; + case StopBits::OneAndHalfStop: + serial_info.StopBits = ONE5STOPBITS; + break; + case StopBits::TwoStop: + serial_info.StopBits = TWOSTOPBITS; + break; + default: + std::cerr << "Invalid stop bits value." << std::endl; + return; + } } -void set_stop_bits(DCB& serial_info, StopBits stop_bits) { - switch (stop_bits) { - case StopBits::OneStop: serial_info.StopBits = ONESTOPBIT; - break; - case StopBits::OneAndHalfStop: serial_info.StopBits = ONE5STOPBITS; - break; - case StopBits::TwoStop: serial_info.StopBits = TWOSTOPBITS; - break; - default: std::cerr << "Invalid stop bits value." << std::endl; - return; - } +StopBits get_stop_bits(DCB &serial_info) { + switch (serial_info.StopBits) { + case ONESTOPBIT: + return StopBits::OneStop; + case ONE5STOPBITS: + return StopBits::OneAndHalfStop; + case TWOSTOPBITS: + return StopBits::TwoStop; + default: + return StopBits::UnknownStopBits; + } } -StopBits get_stop_bits(DCB& serial_info) { - switch (serial_info.StopBits) { - case ONESTOPBIT: return StopBits::OneStop; - case ONE5STOPBITS: return StopBits::OneAndHalfStop; - case TWOSTOPBITS: return StopBits::TwoStop; - default: return StopBits::UnknownStopBits; - } +void set_parity(DCB &serial_info, Parity parity) { + switch (parity) { + case Parity::NoParity: + serial_info.Parity = NOPARITY; + break; + case Parity::EvenParity: + serial_info.Parity = EVENPARITY; + break; + case Parity::OddParity: + serial_info.Parity = ODDPARITY; + break; + case Parity::SpaceParity: + serial_info.Parity = SPACEPARITY; + break; + case Parity::MarkParity: + serial_info.Parity = MARKPARITY; + break; + default: + std::cerr << "Invalid parity value." << std::endl; + return; + } } -void set_parity(DCB& serial_info, Parity parity) { - switch (parity) { - case Parity::NoParity: serial_info.Parity = NOPARITY; - break; - case Parity::EvenParity: serial_info.Parity = EVENPARITY; - break; - case Parity::OddParity: serial_info.Parity = ODDPARITY; - break; - case Parity::SpaceParity: serial_info.Parity = SPACEPARITY; - break; - case Parity::MarkParity: serial_info.Parity = MARKPARITY; - break; - default: std::cerr << "Invalid parity value." << std::endl; - return; - } -} - -Parity get_parity(DCB& serial_info) { - switch (serial_info.Parity) { - case NOPARITY: return Parity::NoParity; - case EVENPARITY: return Parity::EvenParity; - case ODDPARITY: return Parity::OddParity; - case SPACEPARITY: return Parity::SpaceParity; - case MARKPARITY: return Parity::MarkParity; - default: return Parity::UnknownParity; - } +Parity get_parity(DCB &serial_info) { + switch (serial_info.Parity) { + case NOPARITY: + return Parity::NoParity; + case EVENPARITY: + return Parity::EvenParity; + case ODDPARITY: + return Parity::OddParity; + case SPACEPARITY: + return Parity::SpaceParity; + case MARKPARITY: + return Parity::MarkParity; + default: + return Parity::UnknownParity; + } } // 设置流控制 @@ -344,63 +342,64 @@ Parity get_parity(DCB& serial_info) { // 初始化阶段 用于准备就绪信号 // DSR (Data Set Ready)接收端 // DTR (Data Terminal Ready)发送端 -// fInX = TRUE:启用接收端的软件流控,接收端在接收到 XOFF 时暂停接收数据,在接收到 XON 时恢复接收。 -// fOutX = TRUE:启用发送端的软件流控,发送端会根据接收端发送的 XON/XOFF 指令控制数据发送 -void set_flow_control(DCB& serial_info, FlowControl flow_control) { - switch (flow_control) { - case FlowControl::NoFlowControl: - // 关闭所有流控制 - serial_info.fOutxCtsFlow = FALSE; - serial_info.fOutxDsrFlow = FALSE; - serial_info.fInX = FALSE; - serial_info.fOutX = FALSE; - serial_info.fDtrControl = DTR_CONTROL_DISABLE; - serial_info.fRtsControl = RTS_CONTROL_DISABLE; - break; - case FlowControl::HardwareControl: - // 启用硬件流控制 - serial_info.fOutxCtsFlow = TRUE; - serial_info.fOutxDsrFlow = TRUE; - serial_info.fInX = FALSE; - serial_info.fOutX = FALSE; - serial_info.fDtrControl = DTR_CONTROL_ENABLE; - serial_info.fRtsControl = RTS_CONTROL_ENABLE; - break; - case FlowControl::SoftwareControl: - // 启用软件流控制 - serial_info.fOutxCtsFlow = FALSE; - serial_info.fOutxDsrFlow = FALSE; - serial_info.fInX = TRUE; - serial_info.fOutX = TRUE; - serial_info.fDtrControl = DTR_CONTROL_ENABLE; - serial_info.fRtsControl = RTS_CONTROL_ENABLE; - break; - default: std::cerr << "Unknown flow control type." << std::endl; - return; - } +// fInX = TRUE:启用接收端的软件流控,接收端在接收到 XOFF +// 时暂停接收数据,在接收到 XON 时恢复接收。 fOutX = +// TRUE:启用发送端的软件流控,发送端会根据接收端发送的 XON/XOFF +// 指令控制数据发送 +void set_flow_control(DCB &serial_info, FlowControl flow_control) { + switch (flow_control) { + case FlowControl::NoFlowControl: + // 关闭所有流控制 + serial_info.fOutxCtsFlow = FALSE; + serial_info.fOutxDsrFlow = FALSE; + serial_info.fInX = FALSE; + serial_info.fOutX = FALSE; + serial_info.fDtrControl = DTR_CONTROL_DISABLE; + serial_info.fRtsControl = RTS_CONTROL_DISABLE; + break; + case FlowControl::HardwareControl: + // 启用硬件流控制 + serial_info.fOutxCtsFlow = TRUE; + serial_info.fOutxDsrFlow = TRUE; + serial_info.fInX = FALSE; + serial_info.fOutX = FALSE; + serial_info.fDtrControl = DTR_CONTROL_ENABLE; + serial_info.fRtsControl = RTS_CONTROL_ENABLE; + break; + case FlowControl::SoftwareControl: + // 启用软件流控制 + serial_info.fOutxCtsFlow = FALSE; + serial_info.fOutxDsrFlow = FALSE; + serial_info.fInX = TRUE; + serial_info.fOutX = TRUE; + serial_info.fDtrControl = DTR_CONTROL_ENABLE; + serial_info.fRtsControl = RTS_CONTROL_ENABLE; + break; + default: + std::cerr << "Unknown flow control type." << std::endl; + return; + } } // 获取流控制 -FlowControl get_flow_control(DCB& serial_info) { - if (serial_info.fInX && serial_info.fOutX) { - return FlowControl::SoftwareControl; - } else if (serial_info.fOutxCtsFlow && serial_info.fOutxDsrFlow) { - return FlowControl::HardwareControl; - } else if (!serial_info.fOutxCtsFlow && !serial_info.fOutxDsrFlow && !serial_info.fInX && !serial_info.fOutX) { - return FlowControl::NoFlowControl; - } else { - return FlowControl::UnknownFlowControl; - } +FlowControl get_flow_control(DCB &serial_info) { + if (serial_info.fInX && serial_info.fOutX) { + return FlowControl::SoftwareControl; + } else if (serial_info.fOutxCtsFlow && serial_info.fOutxDsrFlow) { + return FlowControl::HardwareControl; + } else if (!serial_info.fOutxCtsFlow && !serial_info.fOutxDsrFlow && + !serial_info.fInX && !serial_info.fOutX) { + return FlowControl::NoFlowControl; + } else { + return FlowControl::UnknownFlowControl; + } } -} +} // namespace Psc::serial #endif - - - - -// int64_t read_data(HANDLE fd, char* data, int64_t maxSize, bool nonBlocking = false) { +// int64_t read_data(HANDLE fd, char* data, int64_t maxSize, bool nonBlocking = +// false) { // DWORD bytesRead = 0; // OVERLAPPED overlapped = {0}; // @@ -425,19 +424,21 @@ FlowControl get_flow_control(DCB& serial_info) { // if (error == ERROR_IO_PENDING) { // if (nonBlocking) { // // 等待操作完成 -// if (WaitForSingleObject(overlapped.hEvent, INFINITE) == WAIT_OBJECT_0) { -// if (GetOverlappedResult(fd, &overlapped, &bytesRead, FALSE)) { +// if (WaitForSingleObject(overlapped.hEvent, INFINITE) == +// WAIT_OBJECT_0) { +// if (GetOverlappedResult(fd, &overlapped, &bytesRead, +// FALSE)) { // CloseHandle(overlapped.hEvent); // return bytesRead; // } else { -// std::cerr << "获取异步操作结果失败,错误代码: " << GetLastError() << std::endl; +// std::cerr << "获取异步操作结果失败,错误代码: " << +// GetLastError() << std::endl; // CloseHandle(overlapped.hEvent); // return -1; // } // } else { -// std::cerr << "等待事件失败,错误代码: " << GetLastError() << std::endl; -// CloseHandle(overlapped.hEvent); -// return -1; +// std::cerr << "等待事件失败,错误代码: " << GetLastError() +// << std::endl; CloseHandle(overlapped.hEvent); return -1; // } // } // return -1; @@ -461,14 +462,15 @@ FlowControl get_flow_control(DCB& serial_info) { // DWORD bytesAvailable = 0; // // 先探测是否有数据 // if (!PeekNamedPipe(fd, NULL, 0, NULL, &bytesAvailable, NULL)) { -// std::cerr << "PeekNamedPipe 失败,错误代码: " << GetLastError() << std::endl; -// return -1; +// std::cerr << "PeekNamedPipe 失败,错误代码: " << GetLastError() << +// std::endl; return -1; // } // if (bytesAvailable > 0) { // DWORD bytesRead = 0; -// if (!ReadFile(fd, data, static_cast(maxSize), &bytesRead, NULL)) { -// std::cerr << "ReadFile 失败,错误代码: " << GetLastError() << std::endl; -// return -1; +// if (!ReadFile(fd, data, static_cast(maxSize), &bytesRead, +// NULL)) { +// std::cerr << "ReadFile 失败,错误代码: " << GetLastError() << +// std::endl; return -1; // } // return bytesRead; // } else { @@ -481,7 +483,8 @@ FlowControl get_flow_control(DCB& serial_info) { // //return read_data(fd, data, maxSize, true); // 返回读取的字节数 // OVERLAPPED overlapped = {}; // DWORD bytesRead = 0; -// if (ReadFile(fd, data, maxSize, &bytesRead, &overlapped) || GetLastError() == ERROR_IO_PENDING) { +// if (ReadFile(fd, data, maxSize, &bytesRead, &overlapped) || +// GetLastError() == ERROR_IO_PENDING) { // std::cout << "bytesRead:" << bytesRead; // if (GetOverlappedResult(fd, &overlapped, &bytesRead, FALSE)) { // return bytesRead; @@ -502,8 +505,8 @@ FlowControl get_flow_control(DCB& serial_info) { // } // // // 发起异步读取操作 -// BOOL result = ReadFile(fd, data, static_cast(maxSize), &bytesRead, &overlapped); -// if (!result) { +// BOOL result = ReadFile(fd, data, static_cast(maxSize), &bytesRead, +// &overlapped); if (!result) { // DWORD err = GetLastError(); // if (err != ERROR_IO_PENDING) { // LOG_ERROR("ReadFile failed"); diff --git a/Core/Shared_Memory/Shared_Memory_linux.cpp b/Core/Shared_Memory/Shared_Memory_linux.cpp index 3aeb10a..82590ae 100644 --- a/Core/Shared_Memory/Shared_Memory_linux.cpp +++ b/Core/Shared_Memory/Shared_Memory_linux.cpp @@ -4,6 +4,8 @@ #include #include +#include "Core/spdlog/export.h" +#include "Shared_Memory.h" #include #include #include @@ -13,156 +15,158 @@ #include #include #include -#include "Core/spdlog/export.h" -#include "Shared_Memory.h" namespace Psc { - bool check_if_shared_memory_exists(const std::string &name) { - int fd = shm_open(name.c_str(), O_RDWR, 0777); - if (fd < 0) { - return false; - } - close(fd); - return true; +bool check_if_shared_memory_exists(const std::string &name) { + int fd = shm_open(name.c_str(), O_RDWR, 0777); + if (fd < 0) { + return false; + } + close(fd); + return true; +} +Shared_Memory::~Shared_Memory() { close(); } +bool Shared_Memory::create(const std::string &name, size_t size) { + m_name = name; + m_size = size; + m_fd = shm_open(name.c_str(), O_CREAT | O_RDWR, 0777); + if (m_fd < 0) + return false; + if (ftruncate(m_fd, size) != 0) + return false; + m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0); + if (fchmod(m_fd, 0777) != 0) { + std::cerr << "修改共享内存权限失败: " << get_error_message() << std::endl; + Psc::fail_fast(); + } + return m_ptr != MAP_FAILED; +} +bool Shared_Memory::open(const std::string &name, size_t size) { + m_name = name; + m_size = size; + m_fd = shm_open(name.c_str(), O_RDWR, 0777); + if (m_fd < 0) + return false; + m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0); + return m_ptr != MAP_FAILED; +} +void Shared_Memory::close() { + // if (m_ptr) { + // munmap(m_ptr, m_size); + // m_ptr = nullptr; + // } + if (m_fd >= 0) { + ::close(m_fd); + m_fd = -1; + } +} +void Shared_Memory::unlink() { + if (!m_name.empty()) + shm_unlink(m_name.c_str()); +} + +struct MutexBlock { + pthread_mutex_t mutex; + std::atomic initialized; // 0 = 未初始化, 1 = 初始化完成 +}; + +Cross_Process_Mutex::Cross_Process_Mutex() {} + +void Cross_Process_Mutex::init(const std::string &mutexName) { + this->m_mutexName = mutexName; + bool creator = false; + + // 第一次创建尝试 O_EXCL,能判断是否首次创建 + m_fd = shm_open(m_mutexName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0777); + if (m_fd >= 0) { + creator = true; + if (ftruncate(m_fd, sizeof(MutexBlock)) < 0) { + std::cout << "跨进程锁" << mutexName << "创建失败 [" + << get_error_message() << "] " << LOG_POS << std::endl; + Psc::fail_fast(); } - Shared_Memory::~Shared_Memory() { - close(); + if (fchmod(m_fd, 0777) != 0) { + std::cerr << "修改共享内存权限失败: " << get_error_message() << LOG_POS + << std::endl; + Psc::fail_fast(); } - bool Shared_Memory::create(const std::string &name, size_t size) { - m_name = name; - m_size = size; - m_fd = shm_open(name.c_str(), O_CREAT | O_RDWR, 0777); - if (m_fd < 0) return false; - if (ftruncate(m_fd, size) != 0) return false; - m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0); - if (fchmod(m_fd, 0777) != 0) { - std::cerr << "修改共享内存权限失败: " << get_error_message() << std::endl; - Psc::fail_fast(); - } - return m_ptr != MAP_FAILED; + } else if (errno == EEXIST) { + // 已经存在,只打开,不改大小 + m_fd = shm_open(m_mutexName.c_str(), O_RDWR, 0777); + if (m_fd < 0) { + std::cout << "跨进程锁" << mutexName << "打开失败 [" + << get_error_message() << "] " << LOG_POS << std::endl; + Psc::fail_fast(); } - bool Shared_Memory::open(const std::string &name, size_t size) { - m_name = name; - m_size = size; - m_fd = shm_open(name.c_str(), O_RDWR, 0777); - if (m_fd < 0) return false; - m_ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0); - return m_ptr != MAP_FAILED; + } else { + std::cout << "跨进程锁" << mutexName << "检测失败 [" << get_error_message() + << "] " << LOG_POS << std::endl; + Psc::fail_fast(); + } + + // 映射 + m_addr = mmap(nullptr, sizeof(MutexBlock), PROT_READ | PROT_WRITE, MAP_SHARED, + m_fd, 0); + if (m_addr == MAP_FAILED) { + std::cout << "跨进程锁" << mutexName << "mmap失败 [" << get_error_message() + << "] " << LOG_POS << std::endl; + Psc::fail_fast(); + } + + auto block = static_cast(m_addr); + + if (creator) { + // 创建者初始化 + memset(&block->mutex, 0, sizeof(pthread_mutex_t)); + block->initialized.store(0, std::memory_order_relaxed); + + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); + pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); + + if (pthread_mutex_init(&block->mutex, &attr) != 0) { + pthread_mutexattr_destroy(&attr); + std::cout << "跨进程锁" << mutexName << "init失败 [" + << get_error_message() << "] " << LOG_POS << std::endl; + Psc::fail_fast(); } - void Shared_Memory::close() { - // if (m_ptr) { - // munmap(m_ptr, m_size); - // m_ptr = nullptr; - // } - if (m_fd >= 0) { - ::close(m_fd); - m_fd = -1; - } - } - void Shared_Memory::unlink() { - if (!m_name.empty()) shm_unlink(m_name.c_str()); + pthread_mutexattr_destroy(&attr); + + block->initialized.store(1, std::memory_order_release); + + } else { + // 后来者等待初始化完成 + auto ib = &block->initialized; + while (ib->load(std::memory_order_acquire) != 1) { + sched_yield(); } + } +} +Cross_Process_Mutex::~Cross_Process_Mutex() { + // if (m_addr) munmap(m_addr, sizeof(MutexBlock)); + // + close(m_fd); +} - struct MutexBlock { - pthread_mutex_t mutex; - std::atomic initialized; // 0 = 未初始化, 1 = 初始化完成 - }; - - Cross_Process_Mutex::Cross_Process_Mutex() { - - } - - void Cross_Process_Mutex::init(const std::string &mutexName) { - this->m_mutexName = mutexName; - bool creator = false; - - // 第一次创建尝试 O_EXCL,能判断是否首次创建 - m_fd = shm_open(m_mutexName.c_str(), O_RDWR | O_CREAT | O_EXCL, 0777); - if (m_fd >= 0) { - creator = true; - if (ftruncate(m_fd, sizeof(MutexBlock)) < 0) { - std::cout << "跨进程锁" << mutexName << "创建失败 [" << get_error_message() << "] " << LOG_POS <(m_addr); - - if (creator) { - // 创建者初始化 - memset(&block->mutex, 0, sizeof(pthread_mutex_t)); - block->initialized.store(0, std::memory_order_relaxed); - - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); - pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); - - if (pthread_mutex_init(&block->mutex, &attr) != 0) { - pthread_mutexattr_destroy(&attr); - std::cout << "跨进程锁" << mutexName << "init失败 [" << get_error_message() << "] " << LOG_POS <initialized.store(1, std::memory_order_release); - - } else { - // 后来者等待初始化完成 - auto ib = &block->initialized; - while (ib->load(std::memory_order_acquire) != 1) { - sched_yield(); - } - } - } - - Cross_Process_Mutex::~Cross_Process_Mutex() { - // if (m_addr) munmap(m_addr, sizeof(MutexBlock)); - // - close(m_fd); - } - - void Cross_Process_Mutex::lock() { - auto block = static_cast(m_addr); - int r = pthread_mutex_lock(&block->mutex); - - if (r == EOWNERDEAD) { - pthread_mutex_consistent(&block->mutex); - } else if (r == ENOTRECOVERABLE) { - throw std::runtime_error("mutex not recoverable"); - } else if (r != 0) { - throw std::runtime_error("pthread_mutex_lock failed"); - } - } - - void Cross_Process_Mutex::unlock() { - auto block = static_cast(m_addr); - pthread_mutex_unlock(&block->mutex); - } +void Cross_Process_Mutex::lock() { + auto block = static_cast(m_addr); + int r = pthread_mutex_lock(&block->mutex); + if (r == EOWNERDEAD) { + pthread_mutex_consistent(&block->mutex); + } else if (r == ENOTRECOVERABLE) { + throw std::runtime_error("mutex not recoverable"); + } else if (r != 0) { + throw std::runtime_error("pthread_mutex_lock failed"); + } +} +void Cross_Process_Mutex::unlock() { + auto block = static_cast(m_addr); + pthread_mutex_unlock(&block->mutex); +} } // namespace Psc #endif diff --git a/Core/Shared_Memory/Shared_Memory_win.cpp b/Core/Shared_Memory/Shared_Memory_win.cpp index 415833f..b932156 100644 --- a/Core/Shared_Memory/Shared_Memory_win.cpp +++ b/Core/Shared_Memory/Shared_Memory_win.cpp @@ -2,172 +2,145 @@ #ifdef _WIN32 #include namespace Psc { - static std::string win_error_msg(DWORD err = GetLastError()) { - LPVOID lpMsgBuf; - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&lpMsgBuf, - 0, NULL); +static std::string win_error_msg(DWORD err = GetLastError()) { + LPVOID lpMsgBuf; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&lpMsgBuf, 0, NULL); - std::string msg = (lpMsgBuf ? (char*)lpMsgBuf : "Unknown error"); - if (lpMsgBuf) LocalFree(lpMsgBuf); - return msg; - } - - - Cross_Process_Mutex::Cross_Process_Mutex() : m_mutexHandle(nullptr) { - - } - void Cross_Process_Mutex::init(const std::string &mutexName) { - m_mutexName = mutexName; - m_mutexHandle = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, m_mutexName.c_str()); - if (!m_mutexHandle) { - DWORD err = GetLastError(); - if (err != ERROR_FILE_NOT_FOUND) { - std::cerr << "OpenMutexA failed: " << win_error_msg(err) << "\n"; - } - - m_mutexHandle = CreateMutexA(NULL, FALSE, m_mutexName.c_str()); - if (!m_mutexHandle) { - std::cerr << "CreateMutexA failed: " << win_error_msg() << "\n"; - Psc::fail_fast(); - } - } - } - - - Cross_Process_Mutex::~Cross_Process_Mutex() { - if (m_mutexHandle != NULL) { - CloseHandle(m_mutexHandle); - } - } - - void Cross_Process_Mutex::lock() { - DWORD waitResult = WaitForSingleObject(m_mutexHandle, INFINITE); - if (waitResult != WAIT_OBJECT_0) { - std::cerr << "WaitForSingleObject failed: " << win_error_msg() << "\n"; - Psc::fail_fast(); - } - } - - // bool Cross_Process_Mutex::lock(DWORD dwMilliseconds) { - // DWORD waitResult = WaitForSingleObject(m_mutexHandle, dwMilliseconds); - // return (waitResult == WAIT_OBJECT_0); - // } - void Cross_Process_Mutex::unlock() { - if (!ReleaseMutex(m_mutexHandle)) { - std::cerr << "ReleaseMutex failed: " << win_error_msg() << "\n"; - } - } - - - - bool check_if_shared_memory_exists(const std::string &name) { - HANDLE hMapFile = OpenFileMappingA(FILE_MAP_READ, FALSE, name.c_str()); - if (!hMapFile) { - DWORD err = GetLastError(); - if (err != ERROR_FILE_NOT_FOUND) { - std::cerr << "OpenFileMappingA failed: " << win_error_msg(err) - << " (checking existence for '" << name << "')\n"; - } - return false; - } - - CloseHandle(hMapFile); - return true; - } - - Shared_Memory::~Shared_Memory() - { - close(); - } - - bool Shared_Memory::create(const std::string& name, size_t size) - { - std::cout << "创建共享内存【" << name << "】" << std::endl; - m_size = size; - - m_handle = CreateFileMappingA( - INVALID_HANDLE_VALUE, - nullptr, - PAGE_READWRITE, - 0, - (DWORD)size, - name.c_str() - ); - - if (!m_handle) { - std::cerr << "CreateFileMappingA failed for name=" << name - << ": " << win_error_msg() << "\n"; - return false; - } - - m_ptr = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, size); - if (!m_ptr) { - std::cerr << "MapViewOfFile failed for name=" << name - << ": " << win_error_msg() << "\n"; - CloseHandle(m_handle); - m_handle = nullptr; - return false; - } - - return true; - } - bool Shared_Memory::open(const std::string& name, size_t size) - { - std::cout << "打开共享内存【" << name << "】" << std::endl; - m_size = size; - - m_handle = OpenFileMappingA( - FILE_MAP_ALL_ACCESS, - FALSE, - name.c_str() - ); - - if (!m_handle) { - std::cerr << "OpenFileMappingA failed for name=" << name - << ": " << win_error_msg() << "\n"; - return false; - } - - m_ptr = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, size); - if (!m_ptr) { - std::cerr << "MapViewOfFile failed for name=" << name - << ": " << win_error_msg() << "\n"; - CloseHandle(m_handle); - m_handle = nullptr; - return false; - } - - return true; - } - - - void Shared_Memory::close() - { - if (m_ptr) { - if (!UnmapViewOfFile(m_ptr)) { - std::cerr << "UnmapViewOfFile failed: " << win_error_msg() << "\n"; - } - m_ptr = nullptr; - } - - if (m_handle) { - if (!CloseHandle(m_handle)) { - std::cerr << "CloseHandle failed: " << win_error_msg() << "\n"; - } - m_handle = nullptr; - } - } - - -void Shared_Memory::unlink() -{ - // Windows 的共享内存对象在最后一个句柄关闭时自动销毁 - // 不需要 shm_unlink 这种东西 + std::string msg = (lpMsgBuf ? (char *)lpMsgBuf : "Unknown error"); + if (lpMsgBuf) + LocalFree(lpMsgBuf); + return msg; } + +Cross_Process_Mutex::Cross_Process_Mutex() : m_mutexHandle(nullptr) {} +void Cross_Process_Mutex::init(const std::string &mutexName) { + m_mutexName = mutexName; + m_mutexHandle = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, m_mutexName.c_str()); + if (!m_mutexHandle) { + DWORD err = GetLastError(); + if (err != ERROR_FILE_NOT_FOUND) { + std::cerr << "OpenMutexA failed: " << win_error_msg(err) << "\n"; + } + + m_mutexHandle = CreateMutexA(NULL, FALSE, m_mutexName.c_str()); + if (!m_mutexHandle) { + std::cerr << "CreateMutexA failed: " << win_error_msg() << "\n"; + Psc::fail_fast(); + } + } } + +Cross_Process_Mutex::~Cross_Process_Mutex() { + if (m_mutexHandle != NULL) { + CloseHandle(m_mutexHandle); + } +} + +void Cross_Process_Mutex::lock() { + DWORD waitResult = WaitForSingleObject(m_mutexHandle, INFINITE); + if (waitResult != WAIT_OBJECT_0) { + std::cerr << "WaitForSingleObject failed: " << win_error_msg() << "\n"; + Psc::fail_fast(); + } +} + +// bool Cross_Process_Mutex::lock(DWORD dwMilliseconds) { +// DWORD waitResult = WaitForSingleObject(m_mutexHandle, dwMilliseconds); +// return (waitResult == WAIT_OBJECT_0); +// } +void Cross_Process_Mutex::unlock() { + if (!ReleaseMutex(m_mutexHandle)) { + std::cerr << "ReleaseMutex failed: " << win_error_msg() << "\n"; + } +} + +bool check_if_shared_memory_exists(const std::string &name) { + HANDLE hMapFile = OpenFileMappingA(FILE_MAP_READ, FALSE, name.c_str()); + if (!hMapFile) { + DWORD err = GetLastError(); + if (err != ERROR_FILE_NOT_FOUND) { + std::cerr << "OpenFileMappingA failed: " << win_error_msg(err) + << " (checking existence for '" << name << "')\n"; + } + return false; + } + + CloseHandle(hMapFile); + return true; +} + +Shared_Memory::~Shared_Memory() { close(); } + +bool Shared_Memory::create(const std::string &name, size_t size) { + std::cout << "创建共享内存【" << name << "】" << std::endl; + m_size = size; + + m_handle = CreateFileMappingA(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, + 0, (DWORD)size, name.c_str()); + + if (!m_handle) { + std::cerr << "CreateFileMappingA failed for name=" << name << ": " + << win_error_msg() << "\n"; + return false; + } + + m_ptr = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, size); + if (!m_ptr) { + std::cerr << "MapViewOfFile failed for name=" << name << ": " + << win_error_msg() << "\n"; + CloseHandle(m_handle); + m_handle = nullptr; + return false; + } + + return true; +} +bool Shared_Memory::open(const std::string &name, size_t size) { + std::cout << "打开共享内存【" << name << "】" << std::endl; + m_size = size; + + m_handle = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, name.c_str()); + + if (!m_handle) { + std::cerr << "OpenFileMappingA failed for name=" << name << ": " + << win_error_msg() << "\n"; + return false; + } + + m_ptr = MapViewOfFile(m_handle, FILE_MAP_ALL_ACCESS, 0, 0, size); + if (!m_ptr) { + std::cerr << "MapViewOfFile failed for name=" << name << ": " + << win_error_msg() << "\n"; + CloseHandle(m_handle); + m_handle = nullptr; + return false; + } + + return true; +} + +void Shared_Memory::close() { + if (m_ptr) { + if (!UnmapViewOfFile(m_ptr)) { + std::cerr << "UnmapViewOfFile failed: " << win_error_msg() << "\n"; + } + m_ptr = nullptr; + } + + if (m_handle) { + if (!CloseHandle(m_handle)) { + std::cerr << "CloseHandle failed: " << win_error_msg() << "\n"; + } + m_handle = nullptr; + } +} + +void Shared_Memory::unlink() { + // Windows 的共享内存对象在最后一个句柄关闭时自动销毁 + // 不需要 shm_unlink 这种东西 +} +} // namespace Psc #endif diff --git a/Core/Statistics/Frequency_Limit.h b/Core/Statistics/Frequency_Limit.h index 8c7012f..0c81cc0 100644 --- a/Core/Statistics/Frequency_Limit.h +++ b/Core/Statistics/Frequency_Limit.h @@ -1,90 +1,84 @@ #pragma once #include "global.h" -template -class Frequency_Limit_T { +template class Frequency_Limit_T { public: - explicit Frequency_Limit_T(double times_per_second = 1.0) - : interval(1.0 / times_per_second), - last(std::chrono::steady_clock::now()) - {} + explicit Frequency_Limit_T(double times_per_second = 1.0) + : interval(1.0 / times_per_second), + last(std::chrono::steady_clock::now()) {} - bool test() { - using namespace std::chrono; + bool test() { + using namespace std::chrono; - std::lock_guard lock(mtx); + std::lock_guard lock(mtx); - auto now = steady_clock::now(); - double dt = duration_cast(now - last).count() * 1e-6; + auto now = steady_clock::now(); + double dt = duration_cast(now - last).count() * 1e-6; - if (dt >= interval) { - last = now; - return true; - } - return false; + if (dt >= interval) { + last = now; + return true; } + return false; + } private: - double interval; - std::chrono::steady_clock::time_point last; - Mutex_Type mtx; + double interval; + std::chrono::steady_clock::time_point last; + Mutex_Type mtx; }; using Frequency_Limit_ST = Frequency_Limit_T; using Frequency_Limit = Frequency_Limit_T; - - -template -class Frequency_Limit_Multi_T { +template class Frequency_Limit_Multi_T { public: - explicit Frequency_Limit_Multi_T(double default_times_per_second = 1.0) - : default_interval_(1.0 / default_times_per_second) {} + explicit Frequency_Limit_Multi_T(double default_times_per_second = 1.0) + : default_interval_(1.0 / default_times_per_second) {} - // 单个类型的状态 - struct Type_Info { - double interval{}; // 秒 - std::chrono::steady_clock::time_point last; - }; + // 单个类型的状态 + struct Type_Info { + double interval{}; // 秒 + std::chrono::steady_clock::time_point last; + }; - // 设置某个类型的频率 - void set_rate(const std::string& type, double times_per_second) { - std::lock_guard lock(mtx_); - map_[type].interval = 1.0 / times_per_second; - // 注意:不重置 last,避免突发放行 + // 设置某个类型的频率 + void set_rate(const std::string &type, double times_per_second) { + std::lock_guard lock(mtx_); + map_[type].interval = 1.0 / times_per_second; + // 注意:不重置 last,避免突发放行 + } + + // 测试是否允许执行 + bool test(const std::string &type) { + using namespace std::chrono; + + const auto now = steady_clock::now(); + + std::lock_guard lock(mtx_); + + auto &info = map_[type]; + + // 第一次使用该 type + if (info.interval == 0.0) { + info.interval = default_interval_; + info.last = now; + return true; } - // 测试是否允许执行 - bool test(const std::string& type) { - using namespace std::chrono; + const double dt = duration_cast>(now - info.last).count(); - const auto now = steady_clock::now(); - - std::lock_guard lock(mtx_); - - auto& info = map_[type]; - - // 第一次使用该 type - if (info.interval == 0.0) { - info.interval = default_interval_; - info.last = now; - return true; - } - - const double dt = - duration_cast>(now - info.last).count(); - - if (dt >= info.interval) { - info.last = now; - return true; - } - - return false; + if (dt >= info.interval) { + info.last = now; + return true; } + return false; + } + private: - double default_interval_; - std::map map_; - Mutex_Type mtx_; + double default_interval_; + std::map map_; + Mutex_Type mtx_; }; using Frequency_Limit_Multi_ST = Frequency_Limit_Multi_T; diff --git a/Core/Statistics/Statistics.h b/Core/Statistics/Statistics.h index 2209507..acda25b 100644 --- a/Core/Statistics/Statistics.h +++ b/Core/Statistics/Statistics.h @@ -9,14 +9,13 @@ protected: [[nodiscard]] static uint64_t get_current_ms() { using namespace std::chrono; - return duration_cast( - steady_clock::now().time_since_epoch() - ).count(); + return duration_cast(steady_clock::now().time_since_epoch()) + .count(); } public: Base_Statistics() : start_time(get_current_ms()) {} - virtual JSON to_json() const = 0; + virtual JSON to_json() const = 0; virtual ~Base_Statistics() = default; unsigned int get_start_time() const { return start_time; } @@ -25,7 +24,6 @@ public: // Speed Statistics 类,继承自 Base_Statistics\ // 单位B/s - class Speed_Statistics : public Base_Statistics { public: double cur_total{}; @@ -33,8 +31,7 @@ public: double average_speed{}; size_t times{}; - Speed_Statistics& operator+=(const Speed_Statistics& rhs) - { + Speed_Statistics &operator+=(const Speed_Statistics &rhs) { this->cur_total += rhs.cur_total; this->instant_speed += rhs.instant_speed; this->average_speed += rhs.average_speed; @@ -42,9 +39,7 @@ public: return *this; } - Speed_Statistics() { - clear(); - } + Speed_Statistics() { clear(); } void clear() { cur_total = 0; @@ -55,11 +50,8 @@ public: [[nodiscard]] JSON to_json() const override { JSON ret = JSON::object(); - // Ret_J(cur_total) - Ret_J(instant_speed) - Ret_J(average_speed) - Ret_J(times) - return ret; + // Ret_J(cur_total) + Ret_J(instant_speed) Ret_J(average_speed) Ret_J(times) return ret; } [[nodiscard]] std::string to_string() const { @@ -82,7 +74,7 @@ public: instant_speed = cur_total / true_period_ms * 1000; // 转换成 KB/s - //instant_speed /= 1024.0f; + // instant_speed /= 1024.0f; // 平均速度 double average_times = 10.0f; @@ -109,20 +101,14 @@ public: size_t times = 0; [[nodiscard]] JSON to_json() const override { JSON ret = JSON::object(); - Ret_J(max) - Ret_J(min) - Ret_J(average) - Ret_J(instant) - return ret; + Ret_J(max) Ret_J(min) Ret_J(average) Ret_J(instant) return ret; } [[nodiscard]] std::string to_string() const { return VAR_STR_5(min, max, average, instant, times); } - Value_Statistics() { - clear(); - } + Value_Statistics() { clear(); } void clear() { max = std::numeric_limits::min(); @@ -157,16 +143,10 @@ public: unsigned int total_max{}; // 总次数 [[nodiscard]] JSON to_json() const override { JSON ret = JSON::object(); - Ret_J(instant) - Ret_J(average) - Ret_J(count) - Ret_J(total) - Ret_J(total_max) - return ret; - } - Probability_Statistics() { - clear(); + Ret_J(instant) Ret_J(average) Ret_J(count) Ret_J(total) + Ret_J(total_max) return ret; } + Probability_Statistics() { clear(); } void clear() { instant = 0; diff --git a/Core/socket/ASIO_Utils.h b/Core/socket/ASIO_Utils.h index 9ac7827..9cdce9f 100644 --- a/Core/socket/ASIO_Utils.h +++ b/Core/socket/ASIO_Utils.h @@ -1,8 +1,8 @@ #pragma once -#include "global.h" -#include "Socket.h" #include "Core/Base/RingBuffer.hpp" +#include "Socket.h" +#include "global.h" #include @@ -19,20 +19,22 @@ namespace Psc::asio_socket { using ASIO_StreamRingBuffer = PSC_ASIO_STREAM_RING_BUFFER; using ASIO_PacketRingBuffer = PSC_ASIO_PACKET_RING_BUFFER; -inline Socket_FD socket_id(const void* ptr) { - return static_cast(reinterpret_cast(ptr)); +inline Socket_FD socket_id(const void *ptr) { + return static_cast(reinterpret_cast(ptr)); } -inline Sockaddr_In endpoint_to_sockaddr(const asio::ip::tcp::endpoint& endpoint) { - return {endpoint.address().to_string(), endpoint.port()}; +inline Sockaddr_In +endpoint_to_sockaddr(const asio::ip::tcp::endpoint &endpoint) { + return {endpoint.address().to_string(), endpoint.port()}; } -inline Sockaddr_In endpoint_to_sockaddr(const asio::ip::udp::endpoint& endpoint) { - return {endpoint.address().to_string(), endpoint.port()}; +inline Sockaddr_In +endpoint_to_sockaddr(const asio::ip::udp::endpoint &endpoint) { + return {endpoint.address().to_string(), endpoint.port()}; } -inline bool would_block(const asio::error_code& ec) { - return ec == asio::error::would_block || ec == asio::error::try_again; +inline bool would_block(const asio::error_code &ec) { + return ec == asio::error::would_block || ec == asio::error::try_again; } } // namespace Psc::asio_socket diff --git a/Core/socket/Socket_Coro.h b/Core/socket/Socket_Coro.h index 3a7c6c1..2ea3e24 100644 --- a/Core/socket/Socket_Coro.h +++ b/Core/socket/Socket_Coro.h @@ -1,11 +1,11 @@ #pragma once #include "ASIO_Utils.h" +#include "Core/Base/Coro_Result.h" #include "TCP_Client.h" #include "TCP_Server.h" #include "UDP_Client.h" #include "UDP_Server.h" -#include "Core/Base/Coro_Result.h" #include @@ -22,156 +22,136 @@ namespace Psc::asio_socket { class TCP_Client_Coro : public TCP_Client { public: - [[nodiscard]] concurrencpp::result connect_coro() - { - auto started = start_connect(); - tick(); - co_return started; - } + [[nodiscard]] concurrencpp::result connect_coro() { + auto started = start_connect(); + tick(); + co_return started; + } - [[nodiscard]] concurrencpp::result tick_coro() - { - tick(); - co_return; - } + [[nodiscard]] concurrencpp::result tick_coro() { + tick(); + co_return; + } - [[nodiscard]] concurrencpp::result read_coro() - { - co_return read(); - } + [[nodiscard]] concurrencpp::result read_coro() { + co_return read(); + } - [[nodiscard]] concurrencpp::result send_coro(std::string data) - { - send(data); - co_return; - } + [[nodiscard]] concurrencpp::result send_coro(std::string data) { + send(data); + co_return; + } - [[nodiscard]] concurrencpp::result close_coro() - { - close(); - co_return; - } + [[nodiscard]] concurrencpp::result close_coro() { + close(); + co_return; + } }; class TCP_Server_Coro : public TCP_Server { public: - [[nodiscard]] concurrencpp::result listen_coro(std::string ip, std::uint32_t port) - { - co_return listen(std::move(ip), port); - } + [[nodiscard]] concurrencpp::result listen_coro(std::string ip, + std::uint32_t port) { + co_return listen(std::move(ip), port); + } - [[nodiscard]] concurrencpp::result listen_coro(Sockaddr_In address) - { - co_return listen(address); - } + [[nodiscard]] concurrencpp::result listen_coro(Sockaddr_In address) { + co_return listen(address); + } - [[nodiscard]] concurrencpp::result tick_coro() - { - tick(); - co_return; - } + [[nodiscard]] concurrencpp::result tick_coro() { + tick(); + co_return; + } - [[nodiscard]] concurrencpp::result flush_clients_coro() - { - flush_clients(); - co_return; - } + [[nodiscard]] concurrencpp::result flush_clients_coro() { + flush_clients(); + co_return; + } - [[nodiscard]] concurrencpp::result write_to_all_clients_coro(std::string data) - { - write_to_all_clients(data); - co_return; - } + [[nodiscard]] concurrencpp::result + write_to_all_clients_coro(std::string data) { + write_to_all_clients(data); + co_return; + } - [[nodiscard]] concurrencpp::result> read_from_all_clients_coro() - { - co_return read_from_all_clients(); - } + [[nodiscard]] concurrencpp::result> + read_from_all_clients_coro() { + co_return read_from_all_clients(); + } - [[nodiscard]] concurrencpp::result> accept_coro() const - { - co_return accept(); - } + [[nodiscard]] concurrencpp::result> + accept_coro() const { + co_return accept(); + } - [[nodiscard]] concurrencpp::result close_coro() - { - close(); - co_return; - } + [[nodiscard]] concurrencpp::result close_coro() { + close(); + co_return; + } }; class UDP_Client_Coro : public UDP_Client { public: - [[nodiscard]] concurrencpp::result connect_coro() - { - co_return connect(); - } + [[nodiscard]] concurrencpp::result connect_coro() { + co_return connect(); + } - [[nodiscard]] concurrencpp::result read_coro() - { - co_return read(); - } + [[nodiscard]] concurrencpp::result read_coro() { + co_return read(); + } - [[nodiscard]] concurrencpp::result tick_coro() - { - tick(); - co_return; - } + [[nodiscard]] concurrencpp::result tick_coro() { + tick(); + co_return; + } - [[nodiscard]] concurrencpp::result send_coro(std::string data) - { - send(data); - co_return; - } + [[nodiscard]] concurrencpp::result send_coro(std::string data) { + send(data); + co_return; + } - [[nodiscard]] concurrencpp::result close_coro() - { - close(); - co_return; - } + [[nodiscard]] concurrencpp::result close_coro() { + close(); + co_return; + } }; class UDP_Server_Coro : public UDP_Server { public: - [[nodiscard]] concurrencpp::result bind_coro() - { - co_return bind(); - } + [[nodiscard]] concurrencpp::result bind_coro() { co_return bind(); } - [[nodiscard]] concurrencpp::result tick_coro() - { - tick(); - co_return; - } + [[nodiscard]] concurrencpp::result tick_coro() { + tick(); + co_return; + } - [[nodiscard]] concurrencpp::result> read_coro() - { - co_return read(); - } + [[nodiscard]] concurrencpp::result> read_coro() { + co_return read(); + } - [[nodiscard]] concurrencpp::result reply_last_peer_coro(std::string data) - { - reply_last_peer(data); - co_return; - } + [[nodiscard]] concurrencpp::result + reply_last_peer_coro(std::string data) { + reply_last_peer(data); + co_return; + } - [[nodiscard]] concurrencpp::result send_to_coro(std::string ip, uint16_t port, std::string data) - { - send_to(ip, port, data); - co_return; - } + [[nodiscard]] concurrencpp::result + send_to_coro(std::string ip, uint16_t port, std::string data) { + send_to(ip, port, data); + co_return; + } - [[nodiscard]] concurrencpp::result write_to_all_clients_coro(std::string msg) - { - write_to_all_clients(msg); - co_return; - } + [[nodiscard]] concurrencpp::result + write_to_all_clients_coro(std::string msg) { + write_to_all_clients(msg); + co_return; + } - [[nodiscard]] concurrencpp::result close_coro() - { - close(); - co_return; - } + [[nodiscard]] concurrencpp::result close_coro() { + close(); + co_return; + } }; } // namespace Psc::asio_socket @@ -179,211 +159,194 @@ public: namespace Psc::asio_socket::coro { struct TCP_Read_Result { - std::vector data; + std::vector data; }; struct UDP_Read_Result { - Sockaddr_In remote; - std::vector data; + Sockaddr_In remote; + std::vector data; }; -inline void throw_if_error(const asio::error_code& ec) -{ - if (ec) { - throw std::system_error(ec); - } +inline void throw_if_error(const asio::error_code &ec) { + if (ec) { + throw std::system_error(ec); + } } -inline concurrencpp::result> -tcp_resolve(asio::ip::tcp::resolver& resolver, - std::string host, - std::uint16_t port) -{ - auto endpoints = co_await Psc::coro::callback_result>( - [&resolver, host = std::move(host), port](auto done) mutable { - resolver.async_resolve( - host, - std::to_string(port), - [done = std::move(done)](const asio::error_code& ec, - asio::ip::tcp::resolver::results_type endpoints) mutable { - if (ec) { - done.set_exception(std::make_exception_ptr(std::system_error(ec))); - return; - } - done(std::make_shared(std::move(endpoints))); - }); - }); - co_return endpoints; +inline concurrencpp::result< + std::shared_ptr> +tcp_resolve(asio::ip::tcp::resolver &resolver, std::string host, + std::uint16_t port) { + auto endpoints = co_await Psc::coro::callback_result< + std::shared_ptr>( + [&resolver, host = std::move(host), port](auto done) mutable { + resolver.async_resolve( + host, std::to_string(port), + [done = std::move(done)]( + const asio::error_code &ec, + asio::ip::tcp::resolver::results_type endpoints) mutable { + if (ec) { + done.set_exception( + std::make_exception_ptr(std::system_error(ec))); + return; + } + done(std::make_shared( + std::move(endpoints))); + }); + }); + co_return endpoints; } inline concurrencpp::result -tcp_connect(asio::ip::tcp::socket& socket, - const asio::ip::tcp::resolver::results_type& endpoints) -{ - struct Result { - asio::error_code ec; - asio::ip::tcp::endpoint endpoint; - }; +tcp_connect(asio::ip::tcp::socket &socket, + const asio::ip::tcp::resolver::results_type &endpoints) { + struct Result { + asio::error_code ec; + asio::ip::tcp::endpoint endpoint; + }; - auto result = co_await Psc::coro::callback_result( - [&socket, &endpoints](auto done) mutable { - asio::async_connect( - socket, - endpoints, - [done = std::move(done)](const asio::error_code& ec, - const asio::ip::tcp::endpoint& endpoint) mutable { - done(Result{ec, endpoint}); - }); - }); + auto result = co_await Psc::coro::callback_result( + [&socket, &endpoints](auto done) mutable { + asio::async_connect( + socket, endpoints, + [done = std::move(done)]( + const asio::error_code &ec, + const asio::ip::tcp::endpoint &endpoint) mutable { + done(Result{ec, endpoint}); + }); + }); - throw_if_error(result.ec); - co_return result.endpoint; + throw_if_error(result.ec); + co_return result.endpoint; } inline concurrencpp::result -tcp_connect(asio::ip::tcp::socket& socket, - asio::ip::tcp::resolver& resolver, - std::string host, - std::uint16_t port) -{ - auto endpoints = co_await tcp_resolve(resolver, std::move(host), port); - co_return co_await tcp_connect(socket, *endpoints); +tcp_connect(asio::ip::tcp::socket &socket, asio::ip::tcp::resolver &resolver, + std::string host, std::uint16_t port) { + auto endpoints = co_await tcp_resolve(resolver, std::move(host), port); + co_return co_await tcp_connect(socket, *endpoints); } inline concurrencpp::result> -tcp_accept(asio::ip::tcp::acceptor& acceptor) -{ - auto socket = std::make_shared(acceptor.get_executor()); +tcp_accept(asio::ip::tcp::acceptor &acceptor) { + auto socket = + std::make_shared(acceptor.get_executor()); - auto ec = co_await Psc::coro::callback_result( - [&acceptor, socket](auto done) mutable { - acceptor.async_accept( - *socket, - [done = std::move(done)](const asio::error_code& ec) mutable { - done(ec); - }); - }); + auto ec = co_await Psc::coro::callback_result( + [&acceptor, socket](auto done) mutable { + acceptor.async_accept( + *socket, [done = std::move(done)]( + const asio::error_code &ec) mutable { done(ec); }); + }); - throw_if_error(ec); - co_return socket; + throw_if_error(ec); + co_return socket; } inline concurrencpp::result -tcp_read_some(asio::ip::tcp::socket& socket, - std::size_t max_size = 16 * 1024) -{ - struct Result { - asio::error_code ec; - std::size_t size{}; - }; +tcp_read_some(asio::ip::tcp::socket &socket, std::size_t max_size = 16 * 1024) { + struct Result { + asio::error_code ec; + std::size_t size{}; + }; - auto buffer = std::make_shared>(max_size); - auto result = co_await Psc::coro::callback_result( - [&socket, buffer](auto done) mutable { - socket.async_read_some( - asio::buffer(*buffer), - [done = std::move(done)](const asio::error_code& ec, - std::size_t size) mutable { - done(Result{ec, size}); - }); - }); + auto buffer = std::make_shared>(max_size); + auto result = co_await Psc::coro::callback_result( + [&socket, buffer](auto done) mutable { + socket.async_read_some( + asio::buffer(*buffer), + [done = std::move(done)](const asio::error_code &ec, + std::size_t size) mutable { + done(Result{ec, size}); + }); + }); - throw_if_error(result.ec); - buffer->resize(result.size); - co_return TCP_Read_Result{std::move(*buffer)}; + throw_if_error(result.ec); + buffer->resize(result.size); + co_return TCP_Read_Result{std::move(*buffer)}; } inline concurrencpp::result -tcp_write(asio::ip::tcp::socket& socket, - std::string data) -{ - struct Result { - asio::error_code ec; - std::size_t size{}; - }; +tcp_write(asio::ip::tcp::socket &socket, std::string data) { + struct Result { + asio::error_code ec; + std::size_t size{}; + }; - auto buffer = std::make_shared(std::move(data)); - auto result = co_await Psc::coro::callback_result( - [&socket, buffer](auto done) mutable { - asio::async_write( - socket, - asio::buffer(*buffer), - [done = std::move(done)](const asio::error_code& ec, - std::size_t size) mutable { - done(Result{ec, size}); - }); - }); + auto buffer = std::make_shared(std::move(data)); + auto result = co_await Psc::coro::callback_result( + [&socket, buffer](auto done) mutable { + asio::async_write(socket, asio::buffer(*buffer), + [done = std::move(done)](const asio::error_code &ec, + std::size_t size) mutable { + done(Result{ec, size}); + }); + }); - throw_if_error(result.ec); - co_return result.size; + throw_if_error(result.ec); + co_return result.size; } inline concurrencpp::result -udp_receive_from(asio::ip::udp::socket& socket, - std::size_t max_size = 16 * 1024) -{ - struct Result { - asio::error_code ec; - std::size_t size{}; - asio::ip::udp::endpoint remote; - }; - - auto buffer = std::make_shared>(max_size); - auto remote = std::make_shared(); - auto result = co_await Psc::coro::callback_result( - [&socket, buffer, remote](auto done) mutable { - socket.async_receive_from( - asio::buffer(*buffer), - *remote, - [done = std::move(done), remote](const asio::error_code& ec, - std::size_t size) mutable { - done(Result{ec, size, *remote}); - }); - }); - - throw_if_error(result.ec); - buffer->resize(result.size); - co_return UDP_Read_Result{endpoint_to_sockaddr(result.remote), std::move(*buffer)}; -} - -inline concurrencpp::result -udp_send_to(asio::ip::udp::socket& socket, - std::string data, - asio::ip::udp::endpoint remote) -{ - struct Result { - asio::error_code ec; - std::size_t size{}; - }; - - auto buffer = std::make_shared(std::move(data)); - auto result = co_await Psc::coro::callback_result( - [&socket, buffer, remote = std::move(remote)](auto done) mutable { - socket.async_send_to( - asio::buffer(*buffer), - remote, - [done = std::move(done)](const asio::error_code& ec, - std::size_t size) mutable { - done(Result{ec, size}); - }); - }); - - throw_if_error(result.ec); - co_return result.size; -} - -inline concurrencpp::result -udp_send_to(asio::ip::udp::socket& socket, - std::string data, - const Sockaddr_In& remote) -{ +udp_receive_from(asio::ip::udp::socket &socket, + std::size_t max_size = 16 * 1024) { + struct Result { asio::error_code ec; - auto address = asio::ip::make_address(remote.ip, ec); - throw_if_error(ec); - co_return co_await udp_send_to( - socket, - std::move(data), - asio::ip::udp::endpoint(address, static_cast(remote.port))); + std::size_t size{}; + asio::ip::udp::endpoint remote; + }; + + auto buffer = std::make_shared>(max_size); + auto remote = std::make_shared(); + auto result = co_await Psc::coro::callback_result( + [&socket, buffer, remote](auto done) mutable { + socket.async_receive_from( + asio::buffer(*buffer), *remote, + [done = std::move(done), remote](const asio::error_code &ec, + std::size_t size) mutable { + done(Result{ec, size, *remote}); + }); + }); + + throw_if_error(result.ec); + buffer->resize(result.size); + co_return UDP_Read_Result{endpoint_to_sockaddr(result.remote), + std::move(*buffer)}; +} + +inline concurrencpp::result +udp_send_to(asio::ip::udp::socket &socket, std::string data, + asio::ip::udp::endpoint remote) { + struct Result { + asio::error_code ec; + std::size_t size{}; + }; + + auto buffer = std::make_shared(std::move(data)); + auto result = co_await Psc::coro::callback_result( + [&socket, buffer, remote = std::move(remote)](auto done) mutable { + socket.async_send_to( + asio::buffer(*buffer), remote, + [done = std::move(done)](const asio::error_code &ec, + std::size_t size) mutable { + done(Result{ec, size}); + }); + }); + + throw_if_error(result.ec); + co_return result.size; +} + +inline concurrencpp::result +udp_send_to(asio::ip::udp::socket &socket, std::string data, + const Sockaddr_In &remote) { + asio::error_code ec; + auto address = asio::ip::make_address(remote.ip, ec); + throw_if_error(ec); + co_return co_await udp_send_to( + socket, std::move(data), + asio::ip::udp::endpoint(address, + static_cast(remote.port))); } } // namespace Psc::asio_socket::coro diff --git a/Core/socket/TCP_Client.cpp b/Core/socket/TCP_Client.cpp index 3e370ce..8bfb565 100644 --- a/Core/socket/TCP_Client.cpp +++ b/Core/socket/TCP_Client.cpp @@ -4,179 +4,202 @@ namespace Psc::asio_socket { -TCP_Client::~TCP_Client() { - close(); -} +TCP_Client::~TCP_Client() { close(); } void TCP_Client::set_state(State s) { - const auto old = state.exchange(s); - if (old != s && on_state_change) on_state_change(old, s); + const auto old = state.exchange(s); + if (old != s && on_state_change) + on_state_change(old, s); } void TCP_Client::create() { - send_buffer.init(max_buffer_size); - recv_buffer.init(max_buffer_size); - connect_pending = false; - read_pending = false; - write_pending = false; - send_storage.clear(); - resolver = std::make_unique(io_context); - socket = std::make_unique(io_context); - socket_fd = socket_id(socket.get()); - set_state(Reconnecting); + send_buffer.init(max_buffer_size); + recv_buffer.init(max_buffer_size); + connect_pending = false; + read_pending = false; + write_pending = false; + send_storage.clear(); + resolver = std::make_unique(io_context); + socket = std::make_unique(io_context); + socket_fd = socket_id(socket.get()); + set_state(Reconnecting); } void TCP_Client::close() { - connect_pending = false; - read_pending = false; - write_pending = false; - if (resolver) { - asio::error_code ec; - resolver->cancel(); - } - if (socket) { - asio::error_code ec; - socket->cancel(ec); - socket->shutdown(asio::ip::tcp::socket::shutdown_both, ec); - socket->close(ec); - } - socket_fd = static_cast(-1); - set_state(Not_Created); + connect_pending = false; + read_pending = false; + write_pending = false; + if (resolver) { + asio::error_code ec; + resolver->cancel(); + } + if (socket) { + asio::error_code ec; + socket->cancel(ec); + socket->shutdown(asio::ip::tcp::socket::shutdown_both, ec); + socket->close(ec); + } + socket_fd = static_cast(-1); + set_state(Not_Created); } void TCP_Client::schedule_recreate() { - connect_pending = false; - read_pending = false; - write_pending = false; - if (resolver) resolver->cancel(); - if (socket) { - asio::error_code ec; - socket->cancel(ec); - socket->close(ec); - } - next_reconnect_tp = std::chrono::steady_clock::now() + std::chrono::milliseconds(reconnect_backoff_ms); - set_state(Reconnecting); + connect_pending = false; + read_pending = false; + write_pending = false; + if (resolver) + resolver->cancel(); + if (socket) { + asio::error_code ec; + socket->cancel(ec); + socket->close(ec); + } + next_reconnect_tp = std::chrono::steady_clock::now() + + std::chrono::milliseconds(reconnect_backoff_ms); + set_state(Reconnecting); } bool TCP_Client::start_connect() { - if (connect_pending || state == Connecting || state == Connected) return true; - if (dest_address.ip.empty() || dest_address.port == 0) { - set_state(Not_Set_Field); - return false; - } - - io_context.restart(); - resolver = std::make_unique(io_context); - socket = std::make_unique(io_context); - connect_pending = true; - set_state(Connecting); - resolver->async_resolve(dest_address.ip, std::to_string(dest_address.port), - [this](const asio::error_code& ec, asio::ip::tcp::resolver::results_type endpoints) { - if (state != Connecting || !socket) return; - if (ec) { - schedule_recreate(); - return; - } - - asio::async_connect(*socket, endpoints, - [this](const asio::error_code& connect_ec, const asio::ip::tcp::endpoint&) { - connect_pending = false; - if (state != Connecting || !socket) return; - if (connect_ec) { - schedule_recreate(); - return; - } - - socket_fd = socket_id(socket.get()); - address = dest_address; - set_state(Connected); - start_read(); - start_write(); - }); - }); + if (connect_pending || state == Connecting || state == Connected) return true; + if (dest_address.ip.empty() || dest_address.port == 0) { + set_state(Not_Set_Field); + return false; + } + + io_context.restart(); + resolver = std::make_unique(io_context); + socket = std::make_unique(io_context); + connect_pending = true; + set_state(Connecting); + resolver->async_resolve( + dest_address.ip, std::to_string(dest_address.port), + [this](const asio::error_code &ec, + asio::ip::tcp::resolver::results_type endpoints) { + if (state != Connecting || !socket) + return; + if (ec) { + schedule_recreate(); + return; + } + + asio::async_connect(*socket, endpoints, + [this](const asio::error_code &connect_ec, + const asio::ip::tcp::endpoint &) { + connect_pending = false; + if (state != Connecting || !socket) + return; + if (connect_ec) { + schedule_recreate(); + return; + } + + socket_fd = socket_id(socket.get()); + address = dest_address; + set_state(Connected); + start_read(); + start_write(); + }); + }); + return true; } void TCP_Client::tick() { - if (state == Reconnecting && std::chrono::steady_clock::now() >= next_reconnect_tp) { - start_connect(); - } - if (state == Connected) { - start_read(); - start_write(); - } + if (state == Reconnecting && + std::chrono::steady_clock::now() >= next_reconnect_tp) { + start_connect(); + } + if (state == Connected) { + start_read(); + start_write(); + } - io_context.restart(); - io_context.poll(); + io_context.restart(); + io_context.poll(); - if (state == Connected) { - start_read(); - start_write(); - } + if (state == Connected) { + start_read(); + start_write(); + } } void TCP_Client::start_read() { - if (read_pending || state != Connected || !socket || !socket->is_open()) return; + if (read_pending || state != Connected || !socket || !socket->is_open()) + return; - read_pending = true; - socket->async_read_some(asio::buffer(recv_storage), - [this](const asio::error_code& ec, std::size_t n) { - read_pending = false; - if (state != Connected) return; - if (ec == asio::error::operation_aborted) return; - if (ec == asio::error::eof || ec == asio::error::connection_reset || ec) { - schedule_recreate(); - return; - } + read_pending = true; + socket->async_read_some(asio::buffer(recv_storage), + [this](const asio::error_code &ec, std::size_t n) { + read_pending = false; + if (state != Connected) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec == asio::error::eof || + ec == asio::error::connection_reset || ec) { + schedule_recreate(); + return; + } - recv_buffer.write_best_effort(recv_storage.data(), n); - start_read(); - }); + recv_buffer.write_best_effort(recv_storage.data(), + n); + start_read(); + }); } void TCP_Client::start_write() { - if (write_pending || state != Connected || !socket || !socket->is_open()) return; + if (write_pending || state != Connected || !socket || !socket->is_open()) + return; - send_storage.resize(16 * 1024); - auto size = send_buffer.peek_best_effort(send_storage.data(), send_storage.size()); - if (size == 0) return; - send_storage.resize(size); + send_storage.resize(16 * 1024); + auto size = + send_buffer.peek_best_effort(send_storage.data(), send_storage.size()); + if (size == 0) + return; + send_storage.resize(size); - write_pending = true; - socket->async_write_some(asio::buffer(send_storage.data(), send_storage.size()), - [this](const asio::error_code& ec, std::size_t sent) { - write_pending = false; - if (state != Connected) return; - if (ec == asio::error::operation_aborted) return; - if (ec) { - schedule_recreate(); - return; - } + write_pending = true; + socket->async_write_some( + asio::buffer(send_storage.data(), send_storage.size()), + [this](const asio::error_code &ec, std::size_t sent) { + write_pending = false; + if (state != Connected) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec) { + schedule_recreate(); + return; + } - send_buffer.skip(sent); - if (sent != 0) start_write(); - }); + send_buffer.skip(sent); + if (sent != 0) + start_write(); + }); } std::string TCP_Client::read() { - std::string ret; - std::array buffer{}; - for (;;) { - auto n = recv_buffer.read_best_effort(buffer.data(), buffer.size()); - if (n == 0) break; - ret.append(buffer.data(), n); - } - return ret; + std::string ret; + std::array buffer{}; + for (;;) { + auto n = recv_buffer.read_best_effort(buffer.data(), buffer.size()); + if (n == 0) + break; + ret.append(buffer.data(), n); + } + return ret; } -void TCP_Client::send(const std::string& data) { - if (data.empty()) return; - send_buffer.write_best_effort(data.data(), data.size()); - if (state == Connected) start_write(); +void TCP_Client::send(const std::string &data) { + if (data.empty()) + return; + send_buffer.write_best_effort(data.data(), data.size()); + if (state == Connected) + start_write(); } std::string TCP_Client::to_string() { - return "TCP_Client:[" + dest_address.to_string() + "]"; + return "TCP_Client:[" + dest_address.to_string() + "]"; } } // namespace Psc::asio_socket diff --git a/Core/socket/TCP_Client.h b/Core/socket/TCP_Client.h index c8eb65a..28fcb5c 100644 --- a/Core/socket/TCP_Client.h +++ b/Core/socket/TCP_Client.h @@ -2,8 +2,8 @@ #include "ASIO_Utils.h" -#include #include +#include #include #include #include @@ -13,51 +13,52 @@ namespace Psc::asio_socket { class TCP_Client : public Socket_Base { public: - ~TCP_Client() override; + ~TCP_Client() override; - void set_buffer_size(size_t size) { max_buffer_size = size; } - void set_dest_address(const Sockaddr_In& a) { dest_address = a; } - void create(); - void tick(); - std::string read(); - void send(const std::string& data); - std::string to_string() override; + void set_buffer_size(size_t size) { max_buffer_size = size; } + void set_dest_address(const Sockaddr_In &a) { dest_address = a; } + void create(); + void tick(); + std::string read(); + void send(const std::string &data); + std::string to_string() override; - enum State { - Not_Created, - Not_Set_Field, - Reconnecting, - Connecting, - Wait_Check, - Connected - }; + enum State { + Not_Created, + Not_Set_Field, + Reconnecting, + Connecting, + Wait_Check, + Connected + }; - void close() override; - std::atomic state{Not_Created}; - void set_state(State s); - std::function on_state_change = nullptr; + void close() override; + std::atomic state{Not_Created}; + void set_state(State s); + std::function on_state_change = + nullptr; protected: - size_t max_buffer_size = 1024 * 1024; - ASIO_StreamRingBuffer send_buffer; - ASIO_StreamRingBuffer recv_buffer; - Sockaddr_In dest_address{}; - int reconnect_backoff_ms = 200; - std::chrono::steady_clock::time_point next_reconnect_tp{}; + size_t max_buffer_size = 1024 * 1024; + ASIO_StreamRingBuffer send_buffer; + ASIO_StreamRingBuffer recv_buffer; + Sockaddr_In dest_address{}; + int reconnect_backoff_ms = 200; + std::chrono::steady_clock::time_point next_reconnect_tp{}; - asio::io_context io_context; - std::unique_ptr resolver; - std::unique_ptr socket; - std::array recv_storage{}; - std::vector send_storage; - bool connect_pending = false; - bool read_pending = false; - bool write_pending = false; + asio::io_context io_context; + std::unique_ptr resolver; + std::unique_ptr socket; + std::array recv_storage{}; + std::vector send_storage; + bool connect_pending = false; + bool read_pending = false; + bool write_pending = false; - void schedule_recreate(); - bool start_connect(); - void start_read(); - void start_write(); + void schedule_recreate(); + bool start_connect(); + void start_read(); + void start_write(); }; } // namespace Psc::asio_socket diff --git a/Core/socket/TCP_Server.cpp b/Core/socket/TCP_Server.cpp index 558d0d3..5b8f872 100644 --- a/Core/socket/TCP_Server.cpp +++ b/Core/socket/TCP_Server.cpp @@ -4,290 +4,325 @@ namespace Psc::asio_socket { -TCP_Server::~TCP_Server() { - close(); -} +TCP_Server::~TCP_Server() { close(); } void TCP_Server::tick() { - if (state == Working) { - start_accept(); - flush_clients(); - } - - io_context.restart(); - io_context.poll(); - - if (state == Working) { - flush_clients(); - cleanup_closed_clients(); - } -} - -TCP_Server & TCP_Server::set_tcp_no_delay(bool value) { - no_delay = value; - return *this; -} - -TCP_Server& TCP_Server::set_connect_system_buffer_size(size_t size) { - connect_system_buffer_size = size; - return *this; -} - -TCP_Server& TCP_Server::set_connect_user_buffer_size(size_t size) { - connect_user_buffer_size = size; - return *this; -} - -TCP_Server& TCP_Server::set_recv_system_buffer_size(size_t size) { - recv_system_buffer_size = size; - return *this; -} - -TCP_Server& TCP_Server::create() { - acceptor = std::make_unique(io_context); - socket_fd = socket_id(acceptor.get()); - state = Not_bind; - return *this; -} - -bool TCP_Server::listen(const std::string& ip, std::uint32_t port) { - return listen(Sockaddr_In(ip, port)); -} - -bool TCP_Server::listen(const Sockaddr_In& addr) { - if (!acceptor) create(); - if (addr.ip.empty() || addr.port == 0) { - state = Not_Set_Field; - return false; - } - - asio::error_code ec; - const auto address_value = asio::ip::make_address(addr.ip, ec); - if (ec) { - state = Not_bind; - return false; - } - - asio::ip::tcp::endpoint endpoint(address_value, static_cast(addr.port)); - acceptor->open(endpoint.protocol(), ec); - if (ec) return false; - acceptor->set_option(asio::socket_base::reuse_address(true), ec); - acceptor->bind(endpoint, ec); - if (ec) { - state = Not_bind; - return false; - } - acceptor->listen(asio::socket_base::max_listen_connections, ec); - if (ec) { - state = Not_Listen; - return false; - } - address = addr; - state = Working; + if (state == Working) { start_accept(); - return true; + flush_clients(); + } + + io_context.restart(); + io_context.poll(); + + if (state == Working) { + flush_clients(); + cleanup_closed_clients(); + } +} + +TCP_Server &TCP_Server::set_tcp_no_delay(bool value) { + no_delay = value; + return *this; +} + +TCP_Server &TCP_Server::set_connect_system_buffer_size(size_t size) { + connect_system_buffer_size = size; + return *this; +} + +TCP_Server &TCP_Server::set_connect_user_buffer_size(size_t size) { + connect_user_buffer_size = size; + return *this; +} + +TCP_Server &TCP_Server::set_recv_system_buffer_size(size_t size) { + recv_system_buffer_size = size; + return *this; +} + +TCP_Server &TCP_Server::create() { + acceptor = std::make_unique(io_context); + socket_fd = socket_id(acceptor.get()); + state = Not_bind; + return *this; +} + +bool TCP_Server::listen(const std::string &ip, std::uint32_t port) { + return listen(Sockaddr_In(ip, port)); +} + +bool TCP_Server::listen(const Sockaddr_In &addr) { + if (!acceptor) + create(); + if (addr.ip.empty() || addr.port == 0) { + state = Not_Set_Field; + return false; + } + + asio::error_code ec; + const auto address_value = asio::ip::make_address(addr.ip, ec); + if (ec) { + state = Not_bind; + return false; + } + + asio::ip::tcp::endpoint endpoint(address_value, + static_cast(addr.port)); + acceptor->open(endpoint.protocol(), ec); + if (ec) + return false; + acceptor->set_option(asio::socket_base::reuse_address(true), ec); + acceptor->bind(endpoint, ec); + if (ec) { + state = Not_bind; + return false; + } + acceptor->listen(asio::socket_base::max_listen_connections, ec); + if (ec) { + state = Not_Listen; + return false; + } + address = addr; + state = Working; + start_accept(); + return true; } void TCP_Server::close() { - accept_pending = false; - if (pending_accept_socket) { - asio::error_code ec; - pending_accept_socket->cancel(ec); - pending_accept_socket->close(ec); - } - pending_accept_socket.reset(); + accept_pending = false; + if (pending_accept_socket) { + asio::error_code ec; + pending_accept_socket->cancel(ec); + pending_accept_socket->close(ec); + } + pending_accept_socket.reset(); - for (auto& [_, conn] : tcp_clients) { - close_client(conn); - } - tcp_clients.clear(); - accepted_clients.clear(); + for (auto &[_, conn] : tcp_clients) { + close_client(conn); + } + tcp_clients.clear(); + accepted_clients.clear(); - if (acceptor) { - asio::error_code ec; - acceptor->cancel(ec); - acceptor->close(ec); - } - socket_fd = static_cast(-1); - state = Not_Created; + if (acceptor) { + asio::error_code ec; + acceptor->cancel(ec); + acceptor->close(ec); + } + socket_fd = static_cast(-1); + state = Not_Created; } std::shared_ptr TCP_Server::accept() const { - while (!accepted_clients.empty()) { - auto conn = accepted_clients.front().lock(); - accepted_clients.erase(accepted_clients.begin()); - if (conn && !conn->closing) return conn; - } - return nullptr; + while (!accepted_clients.empty()) { + auto conn = accepted_clients.front().lock(); + accepted_clients.erase(accepted_clients.begin()); + if (conn && !conn->closing) + return conn; + } + return nullptr; } void TCP_Server::start_accept() { - if (accept_pending || !acceptor || state != Working || !acceptor->is_open()) return; + if (accept_pending || !acceptor || state != Working || !acceptor->is_open()) + return; - pending_accept_socket = std::make_shared(io_context); - accept_pending = true; - acceptor->async_accept(*pending_accept_socket, - [this](const asio::error_code& ec) { - accept_pending = false; - if (state != Working) return; - if (ec == asio::error::operation_aborted) return; - if (!ec && pending_accept_socket) { - asio::error_code option_ec; - pending_accept_socket->set_option(asio::ip::tcp::no_delay(no_delay), option_ec); - pending_accept_socket->set_option( - asio::socket_base::send_buffer_size(static_cast(connect_system_buffer_size)), - option_ec); - pending_accept_socket->set_option( - asio::socket_base::receive_buffer_size(static_cast(recv_system_buffer_size)), - option_ec); + pending_accept_socket = std::make_shared(io_context); + accept_pending = true; + acceptor->async_accept( + *pending_accept_socket, [this](const asio::error_code &ec) { + accept_pending = false; + if (state != Working) + return; + if (ec == asio::error::operation_aborted) + return; + if (!ec && pending_accept_socket) { + asio::error_code option_ec; + pending_accept_socket->set_option(asio::ip::tcp::no_delay(no_delay), + option_ec); + pending_accept_socket->set_option( + asio::socket_base::send_buffer_size( + static_cast(connect_system_buffer_size)), + option_ec); + pending_accept_socket->set_option( + asio::socket_base::receive_buffer_size( + static_cast(recv_system_buffer_size)), + option_ec); - auto conn = std::make_shared(); - conn->socket = pending_accept_socket; - conn->send_buffer.init(connect_user_buffer_size); - conn->recv_buffer.init(connect_user_buffer_size); - conn->info.fd = socket_id(conn->socket.get()); - conn->info.sockaddr = endpoint_to_sockaddr(conn->socket->remote_endpoint(option_ec)); - tcp_clients[conn->info.fd] = conn; - accepted_clients.push_back(conn); - start_read(conn); - start_write(conn); - } - pending_accept_socket.reset(); - start_accept(); - }); + auto conn = std::make_shared(); + conn->socket = pending_accept_socket; + conn->send_buffer.init(connect_user_buffer_size); + conn->recv_buffer.init(connect_user_buffer_size); + conn->info.fd = socket_id(conn->socket.get()); + conn->info.sockaddr = + endpoint_to_sockaddr(conn->socket->remote_endpoint(option_ec)); + tcp_clients[conn->info.fd] = conn; + accepted_clients.push_back(conn); + start_read(conn); + start_write(conn); + } + pending_accept_socket.reset(); + start_accept(); + }); } -void TCP_Server::start_read(const std::shared_ptr& conn) { - if (!conn || conn->closing || conn->read_pending || !conn->socket || !conn->socket->is_open()) return; +void TCP_Server::start_read(const std::shared_ptr &conn) { + if (!conn || conn->closing || conn->read_pending || !conn->socket || + !conn->socket->is_open()) + return; - conn->read_pending = true; - conn->socket->async_read_some(asio::buffer(conn->recv_storage), - [this, conn](const asio::error_code& ec, std::size_t n) { - conn->read_pending = false; - if (conn->closing) return; - if (ec == asio::error::operation_aborted) return; - if (ec == asio::error::eof || ec == asio::error::connection_reset || ec) { - close_client(conn); - return; - } + conn->read_pending = true; + conn->socket->async_read_some( + asio::buffer(conn->recv_storage), + [this, conn](const asio::error_code &ec, std::size_t n) { + conn->read_pending = false; + if (conn->closing) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec == asio::error::eof || ec == asio::error::connection_reset || + ec) { + close_client(conn); + return; + } - conn->recv_buffer.write_best_effort(conn->recv_storage.data(), n); - start_read(conn); - }); + conn->recv_buffer.write_best_effort(conn->recv_storage.data(), n); + start_read(conn); + }); } -void TCP_Server::start_write(const std::shared_ptr& conn) { - if (!conn || conn->closing || conn->write_pending || !conn->socket || !conn->socket->is_open()) return; +void TCP_Server::start_write(const std::shared_ptr &conn) { + if (!conn || conn->closing || conn->write_pending || !conn->socket || + !conn->socket->is_open()) + return; - conn->send_storage.resize(16 * 1024); - auto size = conn->send_buffer.peek_best_effort(conn->send_storage.data(), conn->send_storage.size()); - if (size == 0) return; - conn->send_storage.resize(size); + conn->send_storage.resize(16 * 1024); + auto size = conn->send_buffer.peek_best_effort(conn->send_storage.data(), + conn->send_storage.size()); + if (size == 0) + return; + conn->send_storage.resize(size); - conn->write_pending = true; - conn->socket->async_write_some(asio::buffer(conn->send_storage.data(), conn->send_storage.size()), - [this, conn](const asio::error_code& ec, std::size_t sent) { - conn->write_pending = false; - if (conn->closing) return; - if (ec == asio::error::operation_aborted) return; - if (ec) { - close_client(conn); - return; - } + conn->write_pending = true; + conn->socket->async_write_some( + asio::buffer(conn->send_storage.data(), conn->send_storage.size()), + [this, conn](const asio::error_code &ec, std::size_t sent) { + conn->write_pending = false; + if (conn->closing) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec) { + close_client(conn); + return; + } - conn->send_buffer.skip(sent); - conn->push_speed.update(static_cast(sent)); - conn->send_num.update(static_cast(sent)); - if (sent != 0) start_write(conn); - }); + conn->send_buffer.skip(sent); + conn->push_speed.update(static_cast(sent)); + conn->send_num.update(static_cast(sent)); + if (sent != 0) + start_write(conn); + }); } -void TCP_Server::close_client(const std::shared_ptr& conn) { - if (!conn || conn->closing) return; - conn->closing = true; - if (conn->socket) { - asio::error_code ec; - conn->socket->cancel(ec); - conn->socket->shutdown(asio::ip::tcp::socket::shutdown_both, ec); - conn->socket->close(ec); - } +void TCP_Server::close_client(const std::shared_ptr &conn) { + if (!conn || conn->closing) + return; + conn->closing = true; + if (conn->socket) { + asio::error_code ec; + conn->socket->cancel(ec); + conn->socket->shutdown(asio::ip::tcp::socket::shutdown_both, ec); + conn->socket->close(ec); + } } void TCP_Server::cleanup_closed_clients() { - for (auto it = tcp_clients.begin(); it != tcp_clients.end();) { - if (!it->second || it->second->closing || !it->second->socket || !it->second->socket->is_open()) { - it = tcp_clients.erase(it); - } else { - ++it; - } + for (auto it = tcp_clients.begin(); it != tcp_clients.end();) { + if (!it->second || it->second->closing || !it->second->socket || + !it->second->socket->is_open()) { + it = tcp_clients.erase(it); + } else { + ++it; } + } - for (auto it = accepted_clients.begin(); it != accepted_clients.end();) { - auto conn = it->lock(); - if (!conn || conn->closing) { - it = accepted_clients.erase(it); - } else { - ++it; - } + for (auto it = accepted_clients.begin(); it != accepted_clients.end();) { + auto conn = it->lock(); + if (!conn || conn->closing) { + it = accepted_clients.erase(it); + } else { + ++it; } + } } void TCP_Server::flush_clients() { - start_accept(); - for (auto& [_, conn] : tcp_clients) { - start_read(conn); - start_write(conn); - } + start_accept(); + for (auto &[_, conn] : tcp_clients) { + start_read(conn); + start_write(conn); + } } -void TCP_Server::write_to_all_clients(const std::string& data) { - if (data.empty()) return; - for (auto& [_, conn] : tcp_clients) { - if (!conn || conn->closing) continue; - auto written = conn->send_buffer.write_best_effort(data.data(), data.size()); - if (written < data.size()) conn->lose_speed.update(static_cast(data.size() - written)); - start_write(conn); - } +void TCP_Server::write_to_all_clients(const std::string &data) { + if (data.empty()) + return; + for (auto &[_, conn] : tcp_clients) { + if (!conn || conn->closing) + continue; + auto written = + conn->send_buffer.write_best_effort(data.data(), data.size()); + if (written < data.size()) + conn->lose_speed.update(static_cast(data.size() - written)); + start_write(conn); + } } std::vector TCP_Server::read_from_all_clients() { - std::vector ret; - std::array buffer{}; + std::vector ret; + std::array buffer{}; - for (auto& [_, conn] : tcp_clients) { - if (!conn || conn->closing) continue; + for (auto &[_, conn] : tcp_clients) { + if (!conn || conn->closing) + continue; - std::string data; - for (;;) { - auto n = conn->recv_buffer.read_best_effort(buffer.data(), buffer.size()); - if (n == 0) break; - data.append(buffer.data(), n); - } - if (!data.empty()) ret.push_back({conn->info, std::move(data)}); + std::string data; + for (;;) { + auto n = conn->recv_buffer.read_best_effort(buffer.data(), buffer.size()); + if (n == 0) + break; + data.append(buffer.data(), n); } + if (!data.empty()) + ret.push_back({conn->info, std::move(data)}); + } - cleanup_closed_clients(); - return ret; + cleanup_closed_clients(); + return ret; } std::vector TCP_Server::client_fds() { - std::vector ret; - for (const auto& [fd, conn] : tcp_clients) { - if (conn && !conn->closing) ret.push_back(fd); - } - return ret; + std::vector ret; + for (const auto &[fd, conn] : tcp_clients) { + if (conn && !conn->closing) + ret.push_back(fd); + } + return ret; } std::vector> TCP_Server::get_all_clients() { - std::vector> ret; - for (const auto& [_, conn] : tcp_clients) { - if (conn && !conn->closing) ret.push_back(conn); - } - return ret; + std::vector> ret; + for (const auto &[_, conn] : tcp_clients) { + if (conn && !conn->closing) + ret.push_back(conn); + } + return ret; } std::string TCP_Server::to_string() { - return "TCP_Server:[" + (address ? address->to_string() : std::string{}) + "]"; + return "TCP_Server:[" + (address ? address->to_string() : std::string{}) + + "]"; } } // namespace Psc::asio_socket diff --git a/Core/socket/TCP_Server.h b/Core/socket/TCP_Server.h index 319460e..ead72a6 100644 --- a/Core/socket/TCP_Server.h +++ b/Core/socket/TCP_Server.h @@ -12,78 +12,70 @@ namespace Psc::asio_socket { class TCP_Connect { public: - Accept_Info info; - std::shared_ptr socket; - ASIO_StreamRingBuffer send_buffer; - ASIO_StreamRingBuffer recv_buffer; - Speed_Statistics push_speed; - Speed_Statistics lose_speed; - Value_Statistics send_num; - std::array recv_storage{}; - std::vector send_storage; - bool read_pending = false; - bool write_pending = false; - bool closing = false; + Accept_Info info; + std::shared_ptr socket; + ASIO_StreamRingBuffer send_buffer; + ASIO_StreamRingBuffer recv_buffer; + Speed_Statistics push_speed; + Speed_Statistics lose_speed; + Value_Statistics send_num; + std::array recv_storage{}; + std::vector send_storage; + bool read_pending = false; + bool write_pending = false; + bool closing = false; - [[nodiscard]] std::string to_string() const { - return info.to_string(); - } + [[nodiscard]] std::string to_string() const { return info.to_string(); } }; class TCP_Server : public Socket_Base { public: - ~TCP_Server() override; - void tick(); - TCP_Server& set_tcp_no_delay(bool no_delay); - void close() override; - TCP_Server& create(); - TCP_Server& set_connect_system_buffer_size(size_t size); - TCP_Server& set_connect_user_buffer_size(size_t size); - TCP_Server& set_recv_system_buffer_size(size_t size); - bool listen(const std::string& ip, std::uint32_t port); - bool listen(const Sockaddr_In& address); - std::string to_string() override; - void write_to_all_clients(const std::string& data); + ~TCP_Server() override; + void tick(); + TCP_Server &set_tcp_no_delay(bool no_delay); + void close() override; + TCP_Server &create(); + TCP_Server &set_connect_system_buffer_size(size_t size); + TCP_Server &set_connect_user_buffer_size(size_t size); + TCP_Server &set_recv_system_buffer_size(size_t size); + bool listen(const std::string &ip, std::uint32_t port); + bool listen(const Sockaddr_In &address); + std::string to_string() override; + void write_to_all_clients(const std::string &data); - struct Read_Info { - Accept_Info info; - std::string data; - }; + struct Read_Info { + Accept_Info info; + std::string data; + }; - enum State { - Not_Created, - Not_Set_Field, - Not_bind, - Not_Listen, - Working - }; + enum State { Not_Created, Not_Set_Field, Not_bind, Not_Listen, Working }; - State state = Not_Created; + State state = Not_Created; - std::vector read_from_all_clients(); - std::vector client_fds(); - std::vector> get_all_clients(); - void flush_clients(); - [[nodiscard]] std::shared_ptr accept() const; + std::vector read_from_all_clients(); + std::vector client_fds(); + std::vector> get_all_clients(); + void flush_clients(); + [[nodiscard]] std::shared_ptr accept() const; protected: - mutable asio::io_context io_context; - std::unique_ptr acceptor; - std::map> tcp_clients; - size_t connect_user_buffer_size = 1024 * 1024; - size_t connect_system_buffer_size = 4096 * 10; - size_t max_pending_send_bytes = 1024 * 1024; - size_t recv_system_buffer_size = 1024 * 1024; - bool no_delay = true; - bool accept_pending = false; - std::shared_ptr pending_accept_socket; - mutable std::vector> accepted_clients; + mutable asio::io_context io_context; + std::unique_ptr acceptor; + std::map> tcp_clients; + size_t connect_user_buffer_size = 1024 * 1024; + size_t connect_system_buffer_size = 4096 * 10; + size_t max_pending_send_bytes = 1024 * 1024; + size_t recv_system_buffer_size = 1024 * 1024; + bool no_delay = true; + bool accept_pending = false; + std::shared_ptr pending_accept_socket; + mutable std::vector> accepted_clients; - void start_accept(); - void start_read(const std::shared_ptr& conn); - void start_write(const std::shared_ptr& conn); - void close_client(const std::shared_ptr& conn); - void cleanup_closed_clients(); + void start_accept(); + void start_read(const std::shared_ptr &conn); + void start_write(const std::shared_ptr &conn); + void close_client(const std::shared_ptr &conn); + void cleanup_closed_clients(); }; } // namespace Psc::asio_socket diff --git a/Core/socket/UDP_Client.cpp b/Core/socket/UDP_Client.cpp index da5211e..049756f 100644 --- a/Core/socket/UDP_Client.cpp +++ b/Core/socket/UDP_Client.cpp @@ -3,151 +3,170 @@ namespace Psc::asio_socket { void UDP_Client::create() { - socket = std::make_unique(io_context); - asio::error_code ec; - socket->open(asio::ip::udp::v4(), ec); - connected = false; - connect_pending = false; - read_pending = false; - write_pending = false; - recv_storage.assign(static_cast(read_chunk_size), 0); - send_storage.assign(static_cast(read_chunk_size), 0); - send_buffer.init(user_buffer_size); - recv_buffer.init(user_buffer_size); - state = Not_Set_Field; + socket = std::make_unique(io_context); + asio::error_code ec; + socket->open(asio::ip::udp::v4(), ec); + connected = false; + connect_pending = false; + read_pending = false; + write_pending = false; + recv_storage.assign(static_cast(read_chunk_size), 0); + send_storage.assign(static_cast(read_chunk_size), 0); + send_buffer.init(user_buffer_size); + recv_buffer.init(user_buffer_size); + state = Not_Set_Field; } bool UDP_Client::connect() { - if (connected || connect_pending) return true; - if (!socket) create(); - if (dest_address.ip.empty() || dest_address.port == 0) { - state = Not_Set_Field; - return false; - } - - asio::error_code ec; - endpoint = asio::ip::udp::endpoint(asio::ip::make_address(dest_address.ip, ec), - static_cast(dest_address.port)); - if (ec) { - state = Not_Set_Field; - return false; - } - - io_context.restart(); - connect_pending = true; - state = Connecting; - socket->async_connect(endpoint, [this](const asio::error_code& connect_ec) { - connect_pending = false; - if (connect_ec == asio::error::operation_aborted) return; - if (connect_ec) { - connected = false; - state = Not_Set_Field; - return; - } - - connected = true; - state = Working; - start_read(); - start_write(); - }); + if (connected || connect_pending) return true; + if (!socket) + create(); + if (dest_address.ip.empty() || dest_address.port == 0) { + state = Not_Set_Field; + return false; + } + + asio::error_code ec; + endpoint = + asio::ip::udp::endpoint(asio::ip::make_address(dest_address.ip, ec), + static_cast(dest_address.port)); + if (ec) { + state = Not_Set_Field; + return false; + } + + io_context.restart(); + connect_pending = true; + state = Connecting; + socket->async_connect(endpoint, [this](const asio::error_code &connect_ec) { + connect_pending = false; + if (connect_ec == asio::error::operation_aborted) + return; + if (connect_ec) { + connected = false; + state = Not_Set_Field; + return; + } + + connected = true; + state = Working; + start_read(); + start_write(); + }); + return true; } std::string UDP_Client::read() { - std::string ret(static_cast(read_chunk_size), '\0'); - std::size_t out_len = ret.size(); - if (!recv_buffer.read(ret.data(), out_len)) return {}; - ret.resize(out_len); - return ret; + std::string ret(static_cast(read_chunk_size), '\0'); + std::size_t out_len = ret.size(); + if (!recv_buffer.read(ret.data(), out_len)) + return {}; + ret.resize(out_len); + return ret; } void UDP_Client::tick() { - if (!connected && !connect_pending && !dest_address.ip.empty() && dest_address.port != 0) { - connect(); - } - if (connected) { - start_read(); - start_write(); - } + if (!connected && !connect_pending && !dest_address.ip.empty() && + dest_address.port != 0) { + connect(); + } + if (connected) { + start_read(); + start_write(); + } - io_context.restart(); - io_context.poll(); + io_context.restart(); + io_context.poll(); - if (connected) { - start_read(); - start_write(); - } + if (connected) { + start_read(); + start_write(); + } } -void UDP_Client::send(const std::string& data) { - if (data.empty()) return; - send_buffer.write(data.data(), data.size()); - if (!connected) connect(); - if (connected) start_write(); +void UDP_Client::send(const std::string &data) { + if (data.empty()) + return; + send_buffer.write(data.data(), data.size()); + if (!connected) + connect(); + if (connected) + start_write(); } void UDP_Client::start_read() { - if (read_pending || !connected || !socket || !socket->is_open()) return; - if (recv_storage.empty()) recv_storage.assign(static_cast(read_chunk_size), 0); + if (read_pending || !connected || !socket || !socket->is_open()) + return; + if (recv_storage.empty()) + recv_storage.assign(static_cast(read_chunk_size), 0); - read_pending = true; - socket->async_receive(asio::buffer(recv_storage.data(), recv_storage.size()), - [this](const asio::error_code& ec, std::size_t n) { - read_pending = false; - if (!connected) return; - if (ec == asio::error::operation_aborted) return; - if (ec) { - connected = false; - state = Not_Set_Field; - return; - } + read_pending = true; + socket->async_receive(asio::buffer(recv_storage.data(), recv_storage.size()), + [this](const asio::error_code &ec, std::size_t n) { + read_pending = false; + if (!connected) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec) { + connected = false; + state = Not_Set_Field; + return; + } - recv_buffer.write(recv_storage.data(), n); - start_read(); - }); + recv_buffer.write(recv_storage.data(), n); + start_read(); + }); } void UDP_Client::start_write() { - if (write_pending || !connected || !socket || !socket->is_open()) return; - if (send_storage.empty()) send_storage.assign(static_cast(read_chunk_size), 0); + if (write_pending || !connected || !socket || !socket->is_open()) + return; + if (send_storage.empty()) + send_storage.assign(static_cast(read_chunk_size), 0); - std::size_t out_len = send_storage.size(); - if (!send_buffer.peek(send_storage.data(), out_len)) return; - send_storage.resize(out_len); + std::size_t out_len = send_storage.size(); + if (!send_buffer.peek(send_storage.data(), out_len)) + return; + send_storage.resize(out_len); - write_pending = true; - socket->async_send(asio::buffer(send_storage.data(), send_storage.size()), - [this](const asio::error_code& ec, std::size_t) { - write_pending = false; - if (!connected) return; - if (ec == asio::error::operation_aborted) return; - if (ec) { - connected = false; - state = Not_Set_Field; - return; - } + write_pending = true; + socket->async_send(asio::buffer(send_storage.data(), send_storage.size()), + [this](const asio::error_code &ec, std::size_t) { + write_pending = false; + if (!connected) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec) { + connected = false; + state = Not_Set_Field; + return; + } - send_buffer.skip_one(); - send_storage.assign(static_cast(read_chunk_size), 0); - start_write(); - }); + send_buffer.skip_one(); + send_storage.assign(static_cast(read_chunk_size), + 0); + start_write(); + }); } void UDP_Client::close() { - connected = false; - connect_pending = false; - read_pending = false; - write_pending = false; - if (socket) { - asio::error_code ec; - socket->cancel(ec); - socket->close(ec); - } - state = Not_Created; + connected = false; + connect_pending = false; + read_pending = false; + write_pending = false; + if (socket) { + asio::error_code ec; + socket->cancel(ec); + socket->close(ec); + } + state = Not_Created; } std::string UDP_Client::to_string() { - return "UDP_Client:[" + dest_address.to_string() + "]"; + return "UDP_Client:[" + dest_address.to_string() + "]"; } } // namespace Psc::asio_socket diff --git a/Core/socket/UDP_Client.h b/Core/socket/UDP_Client.h index 089afb7..9e01ec7 100644 --- a/Core/socket/UDP_Client.h +++ b/Core/socket/UDP_Client.h @@ -10,44 +10,46 @@ namespace Psc::asio_socket { class UDP_Client { public: - void set_dest_address(const Sockaddr_In& value) { dest_address = value; } - void set_dest_address(std::string ip, std::uint32_t port) { dest_address = Sockaddr_In(ip, port); } - void create(); - bool connect(); - std::string read(); - void tick(); - void send(const std::string& data); - void close(); - std::string to_string(); + void set_dest_address(const Sockaddr_In &value) { dest_address = value; } + void set_dest_address(std::string ip, std::uint32_t port) { + dest_address = Sockaddr_In(ip, port); + } + void create(); + bool connect(); + std::string read(); + void tick(); + void send(const std::string &data); + void close(); + std::string to_string(); - Sockaddr_In dest_address; + Sockaddr_In dest_address; - enum State { - Not_Created, - Not_Set_Field, - Connecting, - Working, - }; + enum State { + Not_Created, + Not_Set_Field, + Connecting, + Working, + }; - State state = Not_Created; + State state = Not_Created; private: - asio::io_context io_context; - std::unique_ptr socket; - asio::ip::udp::endpoint endpoint; - bool connected = false; - int read_chunk_size = 1024 * 1024; - size_t user_buffer_size = 1024 * 1024; - ASIO_PacketRingBuffer send_buffer; - ASIO_PacketRingBuffer recv_buffer; - std::vector recv_storage; - std::vector send_storage; - bool connect_pending = false; - bool read_pending = false; - bool write_pending = false; + asio::io_context io_context; + std::unique_ptr socket; + asio::ip::udp::endpoint endpoint; + bool connected = false; + int read_chunk_size = 1024 * 1024; + size_t user_buffer_size = 1024 * 1024; + ASIO_PacketRingBuffer send_buffer; + ASIO_PacketRingBuffer recv_buffer; + std::vector recv_storage; + std::vector send_storage; + bool connect_pending = false; + bool read_pending = false; + bool write_pending = false; - void start_read(); - void start_write(); + void start_read(); + void start_write(); }; } // namespace Psc::asio_socket diff --git a/Core/socket/UDP_Server.cpp b/Core/socket/UDP_Server.cpp index 13906cd..96556b1 100644 --- a/Core/socket/UDP_Server.cpp +++ b/Core/socket/UDP_Server.cpp @@ -5,161 +5,188 @@ namespace Psc::asio_socket { void UDP_Server::create() { - socket = std::make_unique(io_context); - socket_fd = socket_id(socket.get()); - recv_buffer.init(buffer_size); - send_buffer.init(buffer_size); - recv_storage.assign(static_cast(read_chunk_size), 0); - send_storage.assign(static_cast(read_chunk_size), 0); - read_pending = false; - write_pending = false; - state = Not_Bind; + socket = std::make_unique(io_context); + socket_fd = socket_id(socket.get()); + recv_buffer.init(buffer_size); + send_buffer.init(buffer_size); + recv_storage.assign(static_cast(read_chunk_size), 0); + send_storage.assign(static_cast(read_chunk_size), 0); + read_pending = false; + write_pending = false; + state = Not_Bind; } bool UDP_Server::bind() { - if (!socket) create(); - if (bind_address.ip.empty() || bind_address.port == 0) { - state = Not_Set_Field; - return false; - } + if (!socket) + create(); + if (bind_address.ip.empty() || bind_address.port == 0) { + state = Not_Set_Field; + return false; + } - asio::error_code ec; - auto address_value = asio::ip::make_address(bind_address.ip, ec); - if (ec) { - state = Not_Bind; - return false; - } + asio::error_code ec; + auto address_value = asio::ip::make_address(bind_address.ip, ec); + if (ec) { + state = Not_Bind; + return false; + } - asio::ip::udp::endpoint endpoint(address_value, static_cast(bind_address.port)); - socket->open(endpoint.protocol(), ec); - if (ec) return false; - socket->set_option(asio::socket_base::reuse_address(true), ec); - socket->set_option(asio::socket_base::receive_buffer_size(static_cast(buffer_size)), ec); - socket->bind(endpoint, ec); - if (ec) { - state = Not_Bind; - return false; - } - bound = true; - state = Working; - start_read(); - return true; + asio::ip::udp::endpoint endpoint( + address_value, static_cast(bind_address.port)); + socket->open(endpoint.protocol(), ec); + if (ec) + return false; + socket->set_option(asio::socket_base::reuse_address(true), ec); + socket->set_option( + asio::socket_base::receive_buffer_size(static_cast(buffer_size)), + ec); + socket->bind(endpoint, ec); + if (ec) { + state = Not_Bind; + return false; + } + bound = true; + state = Working; + start_read(); + return true; } void UDP_Server::tick() { - if (!bound || !socket) return; - start_read(); - start_write(); + if (!bound || !socket) + return; + start_read(); + start_write(); - io_context.restart(); - io_context.poll(); + io_context.restart(); + io_context.poll(); - start_read(); - start_write(); + start_read(); + start_write(); } void UDP_Server::start_read() { - if (read_pending || !bound || !socket || !socket->is_open()) return; - if (recv_storage.empty()) recv_storage.assign(static_cast(read_chunk_size), 0); + if (read_pending || !bound || !socket || !socket->is_open()) + return; + if (recv_storage.empty()) + recv_storage.assign(static_cast(read_chunk_size), 0); - read_pending = true; - socket->async_receive_from(asio::buffer(recv_storage.data(), recv_storage.size()), recv_endpoint, - [this](const asio::error_code& ec, std::size_t n) { - read_pending = false; - if (!bound) return; - if (ec == asio::error::operation_aborted) return; - if (ec) return; + read_pending = true; + socket->async_receive_from( + asio::buffer(recv_storage.data(), recv_storage.size()), recv_endpoint, + [this](const asio::error_code &ec, std::size_t n) { + read_pending = false; + if (!bound) + return; + if (ec == asio::error::operation_aborted) + return; + if (ec) + return; - last_peer = endpoint_to_sockaddr(recv_endpoint); - has_last_peer = true; - if (std::find(clients.begin(), clients.end(), last_peer) == clients.end()) { - clients.push_back(last_peer); - } + last_peer = endpoint_to_sockaddr(recv_endpoint); + has_last_peer = true; + if (std::find(clients.begin(), clients.end(), last_peer) == + clients.end()) { + clients.push_back(last_peer); + } - if (recv_buffer.write(recv_storage.data(), n)) { - recv_peers.push_back(last_peer); - } - start_read(); - }); + if (recv_buffer.write(recv_storage.data(), n)) { + recv_peers.push_back(last_peer); + } + start_read(); + }); } void UDP_Server::start_write() { - if (write_pending || !bound || !socket || !socket->is_open()) return; - if (send_endpoints.empty()) return; - if (send_storage.empty()) send_storage.assign(static_cast(read_chunk_size), 0); + if (write_pending || !bound || !socket || !socket->is_open()) + return; + if (send_endpoints.empty()) + return; + if (send_storage.empty()) + send_storage.assign(static_cast(read_chunk_size), 0); - std::size_t out_len = send_storage.size(); - if (!send_buffer.peek(send_storage.data(), out_len)) return; - send_storage.resize(out_len); - auto endpoint = send_endpoints.front(); + std::size_t out_len = send_storage.size(); + if (!send_buffer.peek(send_storage.data(), out_len)) + return; + send_storage.resize(out_len); + auto endpoint = send_endpoints.front(); - write_pending = true; - socket->async_send_to(asio::buffer(send_storage.data(), send_storage.size()), endpoint, - [this](const asio::error_code& ec, std::size_t) { - write_pending = false; - if (!bound) return; - if (ec == asio::error::operation_aborted) return; - if (!ec) { - send_buffer.skip_one(); - if (!send_endpoints.empty()) send_endpoints.erase(send_endpoints.begin()); - } - send_storage.assign(static_cast(read_chunk_size), 0); - start_write(); - }); + write_pending = true; + socket->async_send_to( + asio::buffer(send_storage.data(), send_storage.size()), endpoint, + [this](const asio::error_code &ec, std::size_t) { + write_pending = false; + if (!bound) + return; + if (ec == asio::error::operation_aborted) + return; + if (!ec) { + send_buffer.skip_one(); + if (!send_endpoints.empty()) + send_endpoints.erase(send_endpoints.begin()); + } + send_storage.assign(static_cast(read_chunk_size), 0); + start_write(); + }); } void UDP_Server::close() { - read_pending = false; - write_pending = false; - if (socket) { - asio::error_code ec; - socket->cancel(ec); - socket->close(ec); - } - clients.clear(); - recv_peers.clear(); - send_endpoints.clear(); - bound = false; - has_last_peer = false; - socket_fd = static_cast(-1); - state = Not_Created; + read_pending = false; + write_pending = false; + if (socket) { + asio::error_code ec; + socket->cancel(ec); + socket->close(ec); + } + clients.clear(); + recv_peers.clear(); + send_endpoints.clear(); + bound = false; + has_last_peer = false; + socket_fd = static_cast(-1); + state = Not_Created; } std::vector UDP_Server::read() { - std::vector ret; - std::string data(static_cast(read_chunk_size), '\0'); + std::vector ret; + std::string data(static_cast(read_chunk_size), '\0'); - while (!recv_peers.empty()) { - std::size_t out_len = data.size(); - if (!recv_buffer.read(data.data(), out_len)) break; - ret.push_back({recv_peers.front(), std::string(data.data(), out_len)}); - recv_peers.erase(recv_peers.begin()); - } - return ret; + while (!recv_peers.empty()) { + std::size_t out_len = data.size(); + if (!recv_buffer.read(data.data(), out_len)) + break; + ret.push_back({recv_peers.front(), std::string(data.data(), out_len)}); + recv_peers.erase(recv_peers.begin()); + } + return ret; } -void UDP_Server::reply_last_peer(const std::string& data) { - if (!has_last_peer) return; - send_to(last_peer.ip, static_cast(last_peer.port), data); +void UDP_Server::reply_last_peer(const std::string &data) { + if (!has_last_peer) + return; + send_to(last_peer.ip, static_cast(last_peer.port), data); } -void UDP_Server::send_to(const std::string& ip, uint16_t port, const std::string& data) { - if (data.empty()) return; - if (!bound && !bind()) return; +void UDP_Server::send_to(const std::string &ip, uint16_t port, + const std::string &data) { + if (data.empty()) + return; + if (!bound && !bind()) + return; - asio::error_code ec; - auto endpoint = asio::ip::udp::endpoint(asio::ip::make_address(ip, ec), port); - if (ec) return; - if (send_buffer.write(data.data(), data.size())) { - send_endpoints.push_back(endpoint); - } - start_write(); + asio::error_code ec; + auto endpoint = asio::ip::udp::endpoint(asio::ip::make_address(ip, ec), port); + if (ec) + return; + if (send_buffer.write(data.data(), data.size())) { + send_endpoints.push_back(endpoint); + } + start_write(); } -void UDP_Server::write_to_all_clients(const std::string& msg) { - for (const auto& client : clients) { - send_to(client.ip, static_cast(client.port), msg); - } +void UDP_Server::write_to_all_clients(const std::string &msg) { + for (const auto &client : clients) { + send_to(client.ip, static_cast(client.port), msg); + } } } // namespace Psc::asio_socket diff --git a/Core/socket/UDP_Server.h b/Core/socket/UDP_Server.h index 4a66c9d..a4877a8 100644 --- a/Core/socket/UDP_Server.h +++ b/Core/socket/UDP_Server.h @@ -10,57 +10,61 @@ namespace Psc::asio_socket { class UDP_Server { public: - void set_bind_address(const Sockaddr_In& addr) { bind_address = addr; } - void set_bind_address(const std::string& ip, std::uint32_t port) { bind_address = Sockaddr_In(ip, port); } - [[nodiscard]] std::string to_string() const { return bind_address.to_string(); } + void set_bind_address(const Sockaddr_In &addr) { bind_address = addr; } + void set_bind_address(const std::string &ip, std::uint32_t port) { + bind_address = Sockaddr_In(ip, port); + } + [[nodiscard]] std::string to_string() const { + return bind_address.to_string(); + } - void create(); - bool bind(); - void tick(); - void close(); - void reply_last_peer(const std::string& data); - void send_to(const std::string& ip, uint16_t port, const std::string& data); - void write_to_all_clients(const std::string& msg); + void create(); + bool bind(); + void tick(); + void close(); + void reply_last_peer(const std::string &data); + void send_to(const std::string &ip, uint16_t port, const std::string &data); + void write_to_all_clients(const std::string &msg); - struct Read_Info { - Sockaddr_In peer; - std::string data; - }; + struct Read_Info { + Sockaddr_In peer; + std::string data; + }; - std::vector read(); + std::vector read(); - enum State { - Not_Created, - Not_Set_Field, - Not_Bind, - Working, - }; + enum State { + Not_Created, + Not_Set_Field, + Not_Bind, + Working, + }; - State state = Not_Created; - Sockaddr_In bind_address; - std::vector clients; - Socket_FD socket_fd = static_cast(-1); - bool bound = false; - int read_chunk_size = 1024 * 1024; - Sockaddr_In last_peer{}; - bool has_last_peer = false; - size_t buffer_size = 4096 * 10; + State state = Not_Created; + Sockaddr_In bind_address; + std::vector clients; + Socket_FD socket_fd = static_cast(-1); + bool bound = false; + int read_chunk_size = 1024 * 1024; + Sockaddr_In last_peer{}; + bool has_last_peer = false; + size_t buffer_size = 4096 * 10; private: - asio::io_context io_context; - std::unique_ptr socket; - asio::ip::udp::endpoint recv_endpoint; - ASIO_PacketRingBuffer recv_buffer; - ASIO_PacketRingBuffer send_buffer; - std::vector recv_peers; - std::vector send_endpoints; - std::vector recv_storage; - std::vector send_storage; - bool read_pending = false; - bool write_pending = false; + asio::io_context io_context; + std::unique_ptr socket; + asio::ip::udp::endpoint recv_endpoint; + ASIO_PacketRingBuffer recv_buffer; + ASIO_PacketRingBuffer send_buffer; + std::vector recv_peers; + std::vector send_endpoints; + std::vector recv_storage; + std::vector send_storage; + bool read_pending = false; + bool write_pending = false; - void start_read(); - void start_write(); + void start_read(); + void start_write(); }; } // namespace Psc::asio_socket diff --git a/Core/socket/export.h b/Core/socket/export.h index b7787aa..355df11 100644 --- a/Core/socket/export.h +++ b/Core/socket/export.h @@ -1,8 +1,8 @@ #pragma once #include "Socket.h" +#include "Socket_Coro.h" #include "TCP_Client.h" #include "TCP_Server.h" #include "UDP_Client.h" #include "UDP_Server.h" -#include "Socket_Coro.h" diff --git a/Core/spdlog/export.cpp b/Core/spdlog/export.cpp index a14bc62..cdc0ae6 100644 --- a/Core/spdlog/export.cpp +++ b/Core/spdlog/export.cpp @@ -12,12 +12,8 @@ #define WIN32_LEAN_AND_MEAN #include "Windows.h" - - #else -std::string handle_fileName(const std::string& utf8_str) { - return utf8_str; -} +std::string handle_fileName(const std::string &utf8_str) { return utf8_str; } #endif #include "../system/export.h" #include "spdlog/async.h" @@ -34,258 +30,237 @@ std::string handle_fileName(const std::string& utf8_str) { namespace fs = std::filesystem; +void spdlog_close() { spdlog::shutdown(); } +Log_Type::Log_Type(std::vector list) : list(list) {} -void spdlog_close() { - spdlog::shutdown(); -} +Log_Type::Log_Type(std::vector> map) + : map(map) {} -Log_Type::Log_Type(std::vector list) : list(list) { - -} - -Log_Type::Log_Type(std::vector> map) : map(map) { - -} - -Log_Type::Log_Type(std::vector list, std::vector> map) : list(list), map(map) { -} +Log_Type::Log_Type(std::vector list, + std::vector> map) + : list(list), map(map) {} std::string get_current_date_string() { - // 获取当前时间 - auto now = std::chrono::system_clock::now(); - auto in_time_t = std::chrono::system_clock::to_time_t(now); + // 获取当前时间 + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); - // 使用 std::put_time 格式化时间 - std::ostringstream oss; - oss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %H:%M:%S"); // 格式化为 "YYYY-MM-DD" - return oss.str(); + // 使用 std::put_time 格式化时间 + std::ostringstream oss; + oss << std::put_time(std::localtime(&in_time_t), + "%Y-%m-%d %H:%M:%S"); // 格式化为 "YYYY-MM-DD" + return oss.str(); } +std::shared_ptr +create_rotating_logger(const std::string &key, size_t byte_size, size_t num) { + std::string fileName = "@/logs/" + key + ".log"; + fileName = Psc::get_abs_path(fileName); + fileName = Psc::utf8_2_platform(fileName); + Psc::create_file_if_not_exists(fileName); + auto rotating_sink = std::make_shared( + fileName, byte_size, num); - - - - -std::shared_ptr create_rotating_logger(const std::string& key, size_t byte_size, size_t num) { - std::string fileName = "@/logs/" + key + ".log"; - fileName = Psc::get_abs_path(fileName); - fileName = Psc::utf8_2_platform(fileName); - Psc::create_file_if_not_exists(fileName); - auto rotating_sink = std::make_shared( - fileName, - byte_size, - num - ); - - - std::vector sinks = {rotating_sink}; - auto logger = std::make_shared( - key, // Logger 名称 - sinks.begin(), sinks.end(), // Sinks 列表 - spdlog::thread_pool(), // 使用初始化的线程池 - spdlog::async_overflow_policy::block // 当队列满时,阻塞写入 - ); - return logger; + std::vector sinks = {rotating_sink}; + auto logger = std::make_shared( + key, // Logger 名称 + sinks.begin(), sinks.end(), // Sinks 列表 + spdlog::thread_pool(), // 使用初始化的线程池 + spdlog::async_overflow_policy::block // 当队列满时,阻塞写入 + ); + return logger; } std::map> day_log_map; -void rotating_log(const std::string& key, const std::string& info, int size, int num) { - try { - if (day_log_map.find(key) == day_log_map.end()) { - day_log_map.insert({key, create_rotating_logger(key, size, num)}); - } - std::shared_ptr daily_logger = day_log_map[key]; - daily_logger->set_pattern("%Y-%m-%d %H:%M:%S [%l] %v"); - daily_logger->info(info); - daily_logger->flush(); - } catch (const spdlog::spdlog_ex& e) { - std::cerr << "Log initialization failed: " << e.what() << std::endl; +void rotating_log(const std::string &key, const std::string &info, int size, + int num) { + try { + if (day_log_map.find(key) == day_log_map.end()) { + day_log_map.insert({key, create_rotating_logger(key, size, num)}); } + std::shared_ptr daily_logger = day_log_map[key]; + daily_logger->set_pattern("%Y-%m-%d %H:%M:%S [%l] %v"); + daily_logger->info(info); + daily_logger->flush(); + } catch (const spdlog::spdlog_ex &e) { + std::cerr << "Log initialization failed: " << e.what() << std::endl; + } } +void pure_log(const std::string &pure_path, const std::string &info, + bool close_after_write) { + auto path = Psc::get_abs_path(pure_path); + static std::map> file_logger_map; + static std::mutex mtx; // 用于保护file_logger_map + static std::mutex mtx2; // 用于保护file_logger_map + static auto create_pure_logger = [](const std::string &fileName) { + Psc::create_file_if_not_exists(fileName); + auto c = spdlog::basic_logger_mt(fileName, fileName); + auto formatter = std::make_unique( + "%v", spdlog::pattern_time_type::local, "", + spdlog::pattern_formatter::custom_flags()); + c->set_formatter(std::move(formatter)); + return c; + }; + if (close_after_write) { + // 用完就关:每次都新建,写完就析构 + std::lock_guard lock(mtx2); // 加锁以保证线程安全 + auto logger = create_pure_logger(path); + logger->log(spdlog::level::info, info); + logger->flush(); -void pure_log(const std::string& pure_path, const std::string& info, bool close_after_write) { - auto path = Psc::get_abs_path(pure_path); - static std::map> file_logger_map; - static std::mutex mtx; // 用于保护file_logger_map - static std::mutex mtx2; // 用于保护file_logger_map - static auto create_pure_logger = [](const std::string& fileName) { - Psc::create_file_if_not_exists( fileName); - auto c = spdlog::basic_logger_mt(fileName, fileName); - auto formatter = std::make_unique("%v", spdlog::pattern_time_type::local, "", spdlog::pattern_formatter::custom_flags()); - c->set_formatter(std::move(formatter)); - return c; - }; - - if (close_after_write) { - // 用完就关:每次都新建,写完就析构 - std::lock_guard lock(mtx2); // 加锁以保证线程安全 - auto logger = create_pure_logger(path); - logger->log(spdlog::level::info, info); - logger->flush(); - - spdlog::drop(path); - // 离开作用域后logger自动析构,文件关闭 - return; - } else { - std::lock_guard lock(mtx); // 加锁以保证线程安全 - auto iter = file_logger_map.find(path); - if (iter == file_logger_map.end()) { - file_logger_map.insert({path, create_pure_logger(path)}); - } - std::shared_ptr logger = file_logger_map[path]; - logger->log(spdlog::level::info, info); - logger->flush(); + spdlog::drop(path); + // 离开作用域后logger自动析构,文件关闭 + return; + } else { + std::lock_guard lock(mtx); // 加锁以保证线程安全 + auto iter = file_logger_map.find(path); + if (iter == file_logger_map.end()) { + file_logger_map.insert({path, create_pure_logger(path)}); } + std::shared_ptr logger = file_logger_map[path]; + logger->log(spdlog::level::info, info); + logger->flush(); + } } -Log_Type& Log_Type::append(std::string key) { - list.push_back(key); - return *this; +Log_Type &Log_Type::append(std::string key) { + list.push_back(key); + return *this; } -Log_Type& Log_Type::append(std::string key, std::string val) { - map.push_back({key, val}); - return *this; +Log_Type &Log_Type::append(std::string key, std::string val) { + map.push_back({key, val}); + return *this; } -std::string Log_Type::to_string() const{ - std::string base; - for (const auto& it : list) { - base += "[" + it + "] "; +std::string Log_Type::to_string() const { + std::string base; + for (const auto &it : list) { + base += "[" + it + "] "; + } + for (const auto &it : map) { + if (new_line) { + base += "\n"; } - for (const auto& it : map) { - if (new_line) { - base += "\n"; - } - base += "[" + it.first + "~" + it.second + "] "; - - } - return base; + base += "[" + it.first + "~" + it.second + "] "; + } + return base; } -Log_Type& Log_Type::set(const std::string& key, std::string val) { - append(key, val); - return *this; +Log_Type &Log_Type::set(const std::string &key, std::string val) { + append(key, val); + return *this; } - namespace spdlog { - struct my_daily_filename_calculator { - // Create filename for the form basename.YYYY-MM-DD - static filename_t calc_filename(const filename_t &filename, const tm &now_tm) { - filename_t basename, ext; - std::tie(basename, ext) = details::file_helper::split_by_extension(filename); +struct my_daily_filename_calculator { + // Create filename for the form basename.YYYY-MM-DD + static filename_t calc_filename(const filename_t &filename, + const tm &now_tm) { + filename_t basename, ext; + std::tie(basename, ext) = + details::file_helper::split_by_extension(filename); + return fmt_lib::format( + SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), + basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, + ext); + } +}; +} // namespace spdlog +BaseLogger::BaseLogger(const std::string &log_path, size_t byte_size, + size_t piece_num) + : log_path(log_path), byte_size(byte_size), piece_num(piece_num) { + std::string path = Psc::get_abs_path(log_path); + Psc::create_file_if_not_exists(path); - return fmt_lib::format( SPDLOG_FMT_STRING(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}")), - basename, - now_tm.tm_year + 1900, - now_tm.tm_mon + 1, - now_tm.tm_mday, - ext); - } - }; + path = Psc::utf8_2_platform(path); + + auto rotating_sink = std::make_shared( + path, byte_size, piece_num); + std::vector sinks = {rotating_sink}; + logger = std::make_shared( + path, // Logger 名称 + sinks.begin(), sinks.end(), // Sinks 列表 + spdlog::thread_pool(), // 使用初始化的线程池 + spdlog::async_overflow_policy::block // 当队列满时,阻塞写入 + ); + // logger->set_level(spdlog::level::debug); + logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v"); } - -BaseLogger::BaseLogger(const std::string& log_path, size_t byte_size, size_t piece_num) -: log_path(log_path), byte_size(byte_size), piece_num(piece_num) { - std::string path = Psc::get_abs_path(log_path); - Psc::create_file_if_not_exists(path); - - path = Psc::utf8_2_platform(path); - - - - - - - auto rotating_sink = std::make_shared( - path, - byte_size, - piece_num - ); - std::vector sinks = {rotating_sink}; - logger = std::make_shared( - path, // Logger 名称 - sinks.begin(), sinks.end(), // Sinks 列表 - spdlog::thread_pool(), // 使用初始化的线程池 - spdlog::async_overflow_policy::block // 当队列满时,阻塞写入 - ); - //logger->set_level(spdlog::level::debug); - logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v"); -} - - Base_Logger_Manager::Base_Logger_Manager() { - spdlog::set_level(spdlog::level::debug); + spdlog::set_level(spdlog::level::debug); } - -Base_Logger_Manager& Base_Logger_Manager::set_thread_num(size_t thread_num) { - this->thread_num = thread_num; - return *this; +Base_Logger_Manager &Base_Logger_Manager::set_thread_num(size_t thread_num) { + this->thread_num = thread_num; + return *this; } -Base_Logger_Manager& Base_Logger_Manager::set_flush_seconds(size_t flush_seconds) { - this->flush_seconds = flush_seconds; - return *this; +Base_Logger_Manager & +Base_Logger_Manager::set_flush_seconds(size_t flush_seconds) { + this->flush_seconds = flush_seconds; + return *this; } -Base_Logger_Manager& Base_Logger_Manager::set_buffer_size(size_t buffer_size) { - this->buffer_size = buffer_size; - return *this; +Base_Logger_Manager &Base_Logger_Manager::set_buffer_size(size_t buffer_size) { + this->buffer_size = buffer_size; + return *this; } void Base_Logger_Manager::init() const { - spdlog::init_thread_pool(buffer_size, thread_num); - spdlog::flush_every(std::chrono::seconds(flush_seconds)); - std::cout << "Base_Logger_Manager sqdlog init thread pool!" + VAR_STR_3(thread_num, flush_seconds, buffer_size) << std::endl; + spdlog::init_thread_pool(buffer_size, thread_num); + spdlog::flush_every(std::chrono::seconds(flush_seconds)); + std::cout << "Base_Logger_Manager sqdlog init thread pool!" + + VAR_STR_3(thread_num, flush_seconds, buffer_size) + << std::endl; } - // 调用 spdlog::shutdown() 会确保: // 所有日志被刷新到磁盘。 // 所有日志器被关闭,相关资源被释放。 Base_Logger_Manager::~Base_Logger_Manager() { - std::ostringstream oss; - oss << "Base_Logger_Manager::~Base_Logger_Manager()" << VAR_STR_3(buffer_size, flush_seconds, thread_num) << std::flush; - spdlog::shutdown(); - oss << "spdlog::shutdown()!\n" << std::flush; - std::cout << oss.str(); + std::ostringstream oss; + oss << "Base_Logger_Manager::~Base_Logger_Manager()" + << VAR_STR_3(buffer_size, flush_seconds, thread_num) << std::flush; + spdlog::shutdown(); + oss << "spdlog::shutdown()!\n" << std::flush; + std::cout << oss.str(); } -std::string BaseLogger::to_log(const Log_Info& log_info) { - return "[" + std::string("func") + "~" + log_info.func_pattern + "] " + log_info.log_type.to_string() + - log_info.content; +std::string BaseLogger::to_log(const Log_Info &log_info) { + return "[" + std::string("func") + "~" + log_info.func_pattern + "] " + + log_info.log_type.to_string() + log_info.content; } - -void BaseLogger::log_main(const Log_Info& log_info) const { - auto msg = to_log(log_info); - if (log_info.console) { - std::cerr << msg + "\n" << std::flush; - } - //logger->log(level, msg); - logger->info(msg); - if(redirect){ - redirect(log_info); - } +void BaseLogger::log_main(const Log_Info &log_info) const { + auto msg = to_log(log_info); + if (log_info.console) { + std::cerr << msg + "\n" << std::flush; + } + // logger->log(level, msg); + logger->info(msg); + if (redirect) { + redirect(log_info); + } } - -void BaseLogger::c_debug(const std::string& func_pattern, const Log_Type& log_type, const std::string& content) { - log_main({true, spdlog::level::debug, func_pattern, log_type, content}); +void BaseLogger::c_debug(const std::string &func_pattern, + const Log_Type &log_type, const std::string &content) { + log_main({true, spdlog::level::debug, func_pattern, log_type, content}); } -void BaseLogger::debug(const std::string& func_pattern, const Log_Type& log_type, const std::string& content) { - log_main({false, spdlog::level::debug, func_pattern, log_type, content}); +void BaseLogger::debug(const std::string &func_pattern, + const Log_Type &log_type, const std::string &content) { + log_main({false, spdlog::level::debug, func_pattern, log_type, content}); } -void BaseLogger::error(const std::string& func_pattern, const Log_Type& log_type, const std::string& content) { - log_main({true, spdlog::level::err, func_pattern, log_type, content}); - logger->flush(); +void BaseLogger::error(const std::string &func_pattern, + const Log_Type &log_type, const std::string &content) { + log_main({true, spdlog::level::err, func_pattern, log_type, content}); + logger->flush(); } diff --git a/Core/system/export.cpp b/Core/system/export.cpp index 664680e..6262fc0 100644 --- a/Core/system/export.cpp +++ b/Core/system/export.cpp @@ -29,8 +29,8 @@ #endif #if defined(_MSC_VER) && defined(_CRTDBG_MAP_ALLOC) -#include #include +#include #endif #ifdef _USE_GTEST @@ -39,328 +39,352 @@ namespace Psc { namespace { - bool local_time_from_time_t(std::time_t value, std::tm& out) noexcept { +bool local_time_from_time_t(std::time_t value, std::tm &out) noexcept { #if defined(_WIN32) - // MinGW / Clang / MSVC 对 localtime_s 支持不完全一致,这里统一用带锁的 std::localtime。 - static std::mutex mtx; - std::lock_guard lock(mtx); - std::tm* tmp = std::localtime(&value); - if (!tmp) { - return false; - } - out = *tmp; - return true; + // MinGW / Clang / MSVC 对 localtime_s 支持不完全一致,这里统一用带锁的 + // std::localtime。 + static std::mutex mtx; + std::lock_guard lock(mtx); + std::tm *tmp = std::localtime(&value); + if (!tmp) { + return false; + } + out = *tmp; + return true; #elif defined(__unix__) || defined(__APPLE__) - return ::localtime_r(&value, &out) != nullptr; + return ::localtime_r(&value, &out) != nullptr; #else - std::tm* tmp = std::localtime(&value); - if (!tmp) { - return false; - } - out = *tmp; - return true; + std::tm *tmp = std::localtime(&value); + if (!tmp) { + return false; + } + out = *tmp; + return true; #endif - } +} +} // namespace + +std::uint64_t get_current_millisecond_timestamp() { + const auto now = std::chrono::system_clock::now(); + const auto duration = std::chrono::duration_cast( + now.time_since_epoch()); + return static_cast(duration.count()); } - std::uint64_t get_current_millisecond_timestamp() { - const auto now = std::chrono::system_clock::now(); - const auto duration = std::chrono::duration_cast(now.time_since_epoch()); - return static_cast(duration.count()); - } - - int redict_main_with_gtest(int argc, char* argv[], Main_Function_Type main_func) { +int redict_main_with_gtest(int argc, char *argv[], + Main_Function_Type main_func) { #if defined(_MSC_VER) && defined(_CRTDBG_MAP_ALLOC) - _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); #endif - set_console_utf8(); + set_console_utf8(); - if (argc == 1) { + if (argc == 1) { #ifdef _USE_GTEST - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); #else - return main_func(argc, argv); + return main_func(argc, argv); #endif - } + } - const int new_argc = argc - 1; - char** new_argv = &argv[1]; + const int new_argc = argc - 1; + char **new_argv = &argv[1]; - int ret = 0; + int ret = 0; #ifdef _USE_GTEST - const std::string type = argv[1]; - if (type != "main") { - ::testing::InitGoogleTest(&argc, argv); - ret = RUN_ALL_TESTS(); - } else { - ret = main_func(new_argc, new_argv); - } + const std::string type = argv[1]; + if (type != "main") { + ::testing::InitGoogleTest(&argc, argv); + ret = RUN_ALL_TESTS(); + } else { + ret = main_func(new_argc, new_argv); + } #else - ret = main_func(new_argc, new_argv); + ret = main_func(new_argc, new_argv); #endif #if defined(_MSC_VER) && defined(_CRTDBG_MAP_ALLOC) - if (_CrtDumpMemoryLeaks()) { - std::cout << "[CRT] Detected memory leaks.\n"; - } else { - std::cout << "[CRT] No memory leaks detected.\n"; - } + if (_CrtDumpMemoryLeaks()) { + std::cout << "[CRT] Detected memory leaks.\n"; + } else { + std::cout << "[CRT] No memory leaks detected.\n"; + } #endif - std::cout << "ecap ret: " << ret << std::endl; - return ret; + std::cout << "ecap ret: " << ret << std::endl; + return ret; +} + +std::string get_exe_dir() { + const std::string exe_path = get_exe_path(); + if (exe_path.empty()) { + return ""; + } + return std::filesystem::path(exe_path).parent_path().string(); +} + +std::string get_abs_path(const std::string &path) { + if (path.empty()) { + return path; + } + + if (path.rfind("@", 0) == 0) { + return get_exe_dir() + path.substr(1); + } + + if (path.rfind("~", 0) == 0) { + return get_home_dir() + path.substr(1); + } + + return path; +} + +std::string utc_2_local_time(std::time_t us_timestamp, const char *format) { + std::tm local_tm{}; + if (!local_time_from_time_t(us_timestamp, local_tm)) { + return "invalid_time"; + } + + std::ostringstream oss; + oss << std::put_time(&local_tm, format ? format : "%H:%M:%S"); + return oss.str(); +} + +namespace { +constexpr std::uint8_t alphabet_map[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +constexpr std::uint8_t invalid_base64 = 255; + +constexpr std::uint8_t decode_char(unsigned char ch) noexcept { + return (ch >= 'A' && ch <= 'Z') ? static_cast(ch - 'A') + : (ch >= 'a' && ch <= 'z') ? static_cast(ch - 'a' + 26) + : (ch >= '0' && ch <= '9') ? static_cast(ch - '0' + 52) + : (ch == '+') ? 62 + : (ch == '/') ? 63 + : (ch == '=') ? 64 + : invalid_base64; +} + +std::uint32_t base64_encode_raw(const std::uint8_t *text, + std::uint32_t text_len, std::uint8_t *encode) { + std::uint32_t i = 0; + std::uint32_t j = 0; + + for (; i + 3 <= text_len; i += 3) { + encode[j++] = alphabet_map[text[i] >> 2]; + encode[j++] = alphabet_map[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)]; + encode[j++] = + alphabet_map[((text[i + 1] << 2) & 0x3c) | (text[i + 2] >> 6)]; + encode[j++] = alphabet_map[text[i + 2] & 0x3f]; + } + + if (i < text_len) { + const std::uint32_t tail = text_len - i; + if (tail == 1) { + encode[j++] = alphabet_map[text[i] >> 2]; + encode[j++] = alphabet_map[(text[i] << 4) & 0x30]; + encode[j++] = '='; + encode[j++] = '='; + } else { + encode[j++] = alphabet_map[text[i] >> 2]; + encode[j++] = alphabet_map[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)]; + encode[j++] = alphabet_map[(text[i + 1] << 2) & 0x3c]; + encode[j++] = '='; + } + } + + return j; +} + +std::uint32_t base64_decode_raw(const std::uint8_t *code, + std::uint32_t code_len, std::uint8_t *plain) { + if (!code || !plain || (code_len & 0x03U) != 0U) { + return 0; + } + + std::uint32_t j = 0; + for (std::uint32_t i = 0; i < code_len; i += 4) { + const std::uint8_t q0 = decode_char(code[i]); + const std::uint8_t q1 = decode_char(code[i + 1]); + const std::uint8_t q2 = decode_char(code[i + 2]); + const std::uint8_t q3 = decode_char(code[i + 3]); + + if (q0 >= 64 || q1 >= 64) { + return j; } - std::string get_exe_dir() { - const std::string exe_path = get_exe_path(); - if (exe_path.empty()) { - return ""; - } - return std::filesystem::path(exe_path).parent_path().string(); + plain[j++] = static_cast((q0 << 2) | (q1 >> 4)); + + if (q2 == 64) { + break; + } + if (q2 > 64) { + return j; } - std::string get_abs_path(const std::string& path) { - if (path.empty()) { - return path; - } + plain[j++] = static_cast((q1 << 4) | (q2 >> 2)); - if (path.rfind("@", 0) == 0) { - return get_exe_dir() + path.substr(1); - } - - if (path.rfind("~", 0) == 0) { - return get_home_dir() + path.substr(1); - } - - return path; + if (q3 == 64) { + break; + } + if (q3 > 64) { + return j; } - std::string utc_2_local_time(std::time_t us_timestamp, const char* format) { - std::tm local_tm{}; - if (!local_time_from_time_t(us_timestamp, local_tm)) { - return "invalid_time"; - } + plain[j++] = static_cast((q2 << 6) | q3); + } - std::ostringstream oss; - oss << std::put_time(&local_tm, format ? format : "%H:%M:%S"); - return oss.str(); - } + return j; +} +} // namespace - namespace { - constexpr std::uint8_t alphabet_map[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - constexpr std::uint8_t invalid_base64 = 255; +std::string base64_encode(const std::string &data) { + const auto text_len = static_cast(data.size()); + std::vector encode(4 * ((text_len + 2) / 3)); + const std::uint32_t encoded_len = + base64_encode_raw(reinterpret_cast(data.data()), + text_len, encode.data()); + return std::string(encode.begin(), encode.begin() + encoded_len); +} - constexpr std::uint8_t decode_char(unsigned char ch) noexcept { - return (ch >= 'A' && ch <= 'Z') ? static_cast(ch - 'A') : - (ch >= 'a' && ch <= 'z') ? static_cast(ch - 'a' + 26) : - (ch >= '0' && ch <= '9') ? static_cast(ch - '0' + 52) : - (ch == '+') ? 62 : - (ch == '/') ? 63 : - (ch == '=') ? 64 : - invalid_base64; - } +std::string base64_decode(const std::string &data) { + const auto code_len = static_cast(data.size()); + if ((code_len & 0x03U) != 0U) { + return ""; + } - std::uint32_t base64_encode_raw(const std::uint8_t* text, std::uint32_t text_len, std::uint8_t* encode) { - std::uint32_t i = 0; - std::uint32_t j = 0; + std::vector plain(code_len * 3 / 4); + const std::uint32_t decoded_len = + base64_decode_raw(reinterpret_cast(data.data()), + code_len, plain.data()); + return std::string(plain.begin(), plain.begin() + decoded_len); +} - for (; i + 3 <= text_len; i += 3) { - encode[j++] = alphabet_map[text[i] >> 2]; - encode[j++] = alphabet_map[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)]; - encode[j++] = alphabet_map[((text[i + 1] << 2) & 0x3c) | (text[i + 2] >> 6)]; - encode[j++] = alphabet_map[text[i + 2] & 0x3f]; - } - - if (i < text_len) { - const std::uint32_t tail = text_len - i; - if (tail == 1) { - encode[j++] = alphabet_map[text[i] >> 2]; - encode[j++] = alphabet_map[(text[i] << 4) & 0x30]; - encode[j++] = '='; - encode[j++] = '='; - } else { - encode[j++] = alphabet_map[text[i] >> 2]; - encode[j++] = alphabet_map[((text[i] << 4) & 0x30) | (text[i + 1] >> 4)]; - encode[j++] = alphabet_map[(text[i + 1] << 2) & 0x3c]; - encode[j++] = '='; - } - } - - return j; - } - - std::uint32_t base64_decode_raw(const std::uint8_t* code, std::uint32_t code_len, std::uint8_t* plain) { - if (!code || !plain || (code_len & 0x03U) != 0U) { - return 0; - } - - std::uint32_t j = 0; - for (std::uint32_t i = 0; i < code_len; i += 4) { - const std::uint8_t q0 = decode_char(code[i]); - const std::uint8_t q1 = decode_char(code[i + 1]); - const std::uint8_t q2 = decode_char(code[i + 2]); - const std::uint8_t q3 = decode_char(code[i + 3]); - - if (q0 >= 64 || q1 >= 64) { - return j; - } - - plain[j++] = static_cast((q0 << 2) | (q1 >> 4)); - - if (q2 == 64) { - break; - } - if (q2 > 64) { - return j; - } - - plain[j++] = static_cast((q1 << 4) | (q2 >> 2)); - - if (q3 == 64) { - break; - } - if (q3 > 64) { - return j; - } - - plain[j++] = static_cast((q2 << 6) | q3); - } - - return j; - } - } - - std::string base64_encode(const std::string& data) { - const auto text_len = static_cast(data.size()); - std::vector encode(4 * ((text_len + 2) / 3)); - const std::uint32_t encoded_len = base64_encode_raw( - reinterpret_cast(data.data()), text_len, encode.data()); - return std::string(encode.begin(), encode.begin() + encoded_len); - } - - std::string base64_decode(const std::string& data) { - const auto code_len = static_cast(data.size()); - if ((code_len & 0x03U) != 0U) { - return ""; - } - - std::vector plain(code_len * 3 / 4); - const std::uint32_t decoded_len = base64_decode_raw( - reinterpret_cast(data.data()), code_len, plain.data()); - return std::string(plain.begin(), plain.begin() + decoded_len); - } - - std::string signal_to_string(int signal) { - switch (signal) { - case SIGINT: return "SIGINT (Ctrl+C)"; - case SIGILL: return "SIGILL (Illegal Instruction)"; - case SIGFPE: return "SIGFPE (Floating Point Exception)"; - case SIGSEGV: return "SIGSEGV (Segmentation Fault)"; - case SIGTERM: return "SIGTERM (Termination Request)"; - case SIGABRT: return "SIGABRT (Abort Signal)"; +std::string signal_to_string(int signal) { + switch (signal) { + case SIGINT: + return "SIGINT (Ctrl+C)"; + case SIGILL: + return "SIGILL (Illegal Instruction)"; + case SIGFPE: + return "SIGFPE (Floating Point Exception)"; + case SIGSEGV: + return "SIGSEGV (Segmentation Fault)"; + case SIGTERM: + return "SIGTERM (Termination Request)"; + case SIGABRT: + return "SIGABRT (Abort Signal)"; #if defined(_WIN32) && defined(SIGBREAK) - case SIGBREAK: return "SIGBREAK (Breakpoint)"; + case SIGBREAK: + return "SIGBREAK (Breakpoint)"; #endif #if defined(_MSC_VER) && defined(SIGABRT_COMPAT) - case SIGABRT_COMPAT: return "SIGABRT_COMPAT (Abort Compatibility Signal)"; + case SIGABRT_COMPAT: + return "SIGABRT_COMPAT (Abort Compatibility Signal)"; #endif - default: return "Unknown signal:" + std::to_string(signal); - } + default: + return "Unknown signal:" + std::to_string(signal); + } +} + +std::string get_current_time_as_string() { + const auto now = std::chrono::system_clock::now(); + const std::time_t now_time = std::chrono::system_clock::to_time_t(now); + + std::tm local_tm{}; + if (!local_time_from_time_t(now_time, local_tm)) { + return "invalid_time"; + } + + std::ostringstream ss; + ss << std::put_time(&local_tm, "%Y-%m-%d_%H-%M-%S"); + return ss.str(); +} + +namespace fs = std::filesystem; + +void create_file_if_not_exists(const std::string &file_name) { + std::error_code ec; + const fs::path file_path(file_name); + + if (fs::exists(file_path, ec)) { + return; + } + + const fs::path parent = file_path.parent_path(); + if (!parent.empty()) { + fs::create_directories(parent, ec); + if (ec) { + std::cerr << "Failed to create parent directory: " << parent.string() + << ", error: " << ec.message() << std::endl; + return; } + } - std::string get_current_time_as_string() { - const auto now = std::chrono::system_clock::now(); - const std::time_t now_time = std::chrono::system_clock::to_time_t(now); + std::ofstream ofs(file_path, std::ios::out | std::ios::app); + if (!ofs) { + std::cerr << "Failed to create the file: " << file_name << std::endl; + return; + } - std::tm local_tm{}; - if (!local_time_from_time_t(now_time, local_tm)) { - return "invalid_time"; - } + const auto perms = + fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all; + fs::permissions(file_path, perms, ec); +} - std::ostringstream ss; - ss << std::put_time(&local_tm, "%Y-%m-%d_%H-%M-%S"); - return ss.str(); +void create_dir_if_not_exists(const std::string &dir_name) { + std::error_code ec; + const fs::path dir_path(dir_name); + + if (!fs::exists(dir_path, ec)) { + fs::create_directories(dir_path, ec); + if (ec) { + std::cerr << "Failed to create directory: " << dir_name + << ", error: " << ec.message() << std::endl; + return; } + } - namespace fs = std::filesystem; + const auto perms = + fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all; + fs::permissions(dir_path, perms, ec); +} - void create_file_if_not_exists(const std::string& file_name) { - std::error_code ec; - const fs::path file_path(file_name); +void write_stack_trace_to_file(const std::string &stack_trace, + const std::string &filename) { + create_file_if_not_exists(filename); + std::ofstream out_file(filename, std::ios::out | std::ios::app); + if (out_file.is_open()) { + out_file << stack_trace << std::endl; + } else { + std::cerr << "Unable to open file " << filename << " for writing." + << std::endl; + } +} - if (fs::exists(file_path, ec)) { - return; - } +void signal_handler(int signal_code) { + std::cout << "signal_handler [" << signal_to_string(signal_code) << "]" + << std::endl; + stop_program = signal_code; +} - const fs::path parent = file_path.parent_path(); - if (!parent.empty()) { - fs::create_directories(parent, ec); - if (ec) { - std::cerr << "Failed to create parent directory: " << parent.string() - << ", error: " << ec.message() << std::endl; - return; - } - } +void signal_handler_ignore(int) {} - std::ofstream ofs(file_path, std::ios::out | std::ios::app); - if (!ofs) { - std::cerr << "Failed to create the file: " << file_name << std::endl; - return; - } +void init_signal_config(std::set normal_quit, + std::set ignore_signal) { + if (is_big_endian) { + std::cout << "大端序 This system is Big-endian." << std::endl; + } else { + std::cout << "小端序 This system is Little-endian." << std::endl; + } - const auto perms = fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all; - fs::permissions(file_path, perms, ec); - } - - void create_dir_if_not_exists(const std::string& dir_name) { - std::error_code ec; - const fs::path dir_path(dir_name); - - if (!fs::exists(dir_path, ec)) { - fs::create_directories(dir_path, ec); - if (ec) { - std::cerr << "Failed to create directory: " << dir_name - << ", error: " << ec.message() << std::endl; - return; - } - } - - const auto perms = fs::perms::owner_all | fs::perms::group_all | fs::perms::others_all; - fs::permissions(dir_path, perms, ec); - } - - void write_stack_trace_to_file(const std::string& stack_trace, const std::string& filename) { - create_file_if_not_exists(filename); - std::ofstream out_file(filename, std::ios::out | std::ios::app); - if (out_file.is_open()) { - out_file << stack_trace << std::endl; - } else { - std::cerr << "Unable to open file " << filename << " for writing." << std::endl; - } - } - - void signal_handler(int signal_code) { - std::cout << "signal_handler [" << signal_to_string(signal_code) << "]" << std::endl; - stop_program = signal_code; - } - - void signal_handler_ignore(int) {} - - void init_signal_config(std::set normal_quit, std::set ignore_signal) { - if (is_big_endian) { - std::cout << "大端序 This system is Big-endian." << std::endl; - } else { - std::cout << "小端序 This system is Little-endian." << std::endl; - } - - for (auto signum : normal_quit) { - std::signal(signum, signal_handler); - } - for (auto signum : ignore_signal) { - std::signal(signum, signal_handler_ignore); - } - } + for (auto signum : normal_quit) { + std::signal(signum, signal_handler); + } + for (auto signum : ignore_signal) { + std::signal(signum, signal_handler_ignore); + } +} } // namespace Psc diff --git a/Core/system/export.h b/Core/system/export.h index 0b37cbc..080493a 100644 --- a/Core/system/export.h +++ b/Core/system/export.h @@ -2,7 +2,6 @@ #include "../Base/global_include.h" - #include #include #include @@ -24,228 +23,227 @@ #include "3rd/magic_enum/export.h" #include "magic_enum/magic_enum.hpp" -#define PSC_LOAD_LIBRARY_PARAMS(M, SEP) \ - M(const std::string&, library_path) +#define PSC_LOAD_LIBRARY_PARAMS(M, SEP) M(const std::string &, library_path) -#define PSC_LOAD_FUNCTION_PARAMS(M, SEP) \ - M(void*, library) SEP() \ - M(const std::string&, function_name) +#define PSC_LOAD_FUNCTION_PARAMS(M, SEP) \ + M(void *, library) SEP() M(const std::string &, function_name) -#define DELETE_COPY(Class) \ - Class(const Class&) = delete; \ - Class& operator=(const Class&) = delete; +#define DELETE_COPY(Class) \ + Class(const Class &) = delete; \ + Class &operator=(const Class &) = delete; namespace Psc { - void set_console_utf8(); +void set_console_utf8(); - std::string get_stack_trace(); - std::string get_computer_serial_number(); +std::string get_stack_trace(); +std::string get_computer_serial_number(); - PSC_DECLARE_TRIPLE_API(void*, load_library, PSC_LOAD_LIBRARY_PARAMS); - void* load_library_fail_fast(const std::string& library_path); +PSC_DECLARE_TRIPLE_API(void *, load_library, PSC_LOAD_LIBRARY_PARAMS); +void *load_library_fail_fast(const std::string &library_path); - void free_library(void* library); +void free_library(void *library); - PSC_DECLARE_TRIPLE_API(void*, load_function, PSC_LOAD_FUNCTION_PARAMS); - void* load_function_fail_fast(void* library, const std::string& function_name); +PSC_DECLARE_TRIPLE_API(void *, load_function, PSC_LOAD_FUNCTION_PARAMS); +void *load_function_fail_fast(void *library, const std::string &function_name); - std::string get_home_dir(); - std::string get_exe_path(); - std::string get_exe_dir(); +std::string get_home_dir(); +std::string get_exe_path(); +std::string get_exe_dir(); - std::string get_abs_path(const std::string& path); - std::string to_upper_case(const std::string& input); - std::string base64_encode(const std::string& data); - std::string base64_decode(const std::string& data); +std::string get_abs_path(const std::string &path); +std::string to_upper_case(const std::string &input); +std::string base64_encode(const std::string &data); +std::string base64_decode(const std::string &data); - // strftime 格式,例如 "%Y-%m-%d %H:%M:%S" / "%H:%M:%S"。 - std::string utc_2_local_time(std::time_t us_timestamp, const char* format = "%H:%M:%S"); +// strftime 格式,例如 "%Y-%m-%d %H:%M:%S" / "%H:%M:%S"。 +std::string utc_2_local_time(std::time_t us_timestamp, + const char *format = "%H:%M:%S"); - std::uint64_t get_current_millisecond_timestamp(); - void set_current_thread_name(const std::string& name); +std::uint64_t get_current_millisecond_timestamp(); +void set_current_thread_name(const std::string &name); - using Main_Function_Type = int (*)(int, char**); +using Main_Function_Type = int (*)(int, char **); - // 接管 main 函数,联通 gtest。 - int redict_main_with_gtest(int argc, char* argv[], Main_Function_Type main_func); +// 接管 main 函数,联通 gtest。 +int redict_main_with_gtest(int argc, char *argv[], + Main_Function_Type main_func); - // 设置给定 std::thread 的优先级。 - // Windows: void* 版本要求传 Win32 HANDLE。 - // Linux: void* 版本要求传 pthread_t*,例如 pthread_t pt = pthread_self(); set_thread_priority(&pt, ...)。 - bool set_thread_priority(void* thread, int priority, bool realtime); - bool set_thread_priority(std::thread* thread, int priority, bool realtime); +// 设置给定 std::thread 的优先级。 +// Windows: void* 版本要求传 Win32 HANDLE。 +// Linux: void* 版本要求传 pthread_t*,例如 pthread_t pt = pthread_self(); +// set_thread_priority(&pt, ...)。 +bool set_thread_priority(void *thread, int priority, bool realtime); +bool set_thread_priority(std::thread *thread, int priority, bool realtime); - // 设置给定线程的 CPU 亲和性。 - // Windows: void* 版本要求传 Win32 HANDLE。 - // Linux: void* 版本要求传 pthread_t*。 - bool set_thread_affinity(void* thread, unsigned cpu_index); - bool set_thread_affinity(std::thread* thread, unsigned cpu_index); +// 设置给定线程的 CPU 亲和性。 +// Windows: void* 版本要求传 Win32 HANDLE。 +// Linux: void* 版本要求传 pthread_t*。 +bool set_thread_affinity(void *thread, unsigned cpu_index); +bool set_thread_affinity(std::thread *thread, unsigned cpu_index); - size_t get_system_memory(); - size_t get_process_memory(); - std::string get_memory_info(); +size_t get_system_memory(); +size_t get_process_memory(); +std::string get_memory_info(); - std::string signal_to_string(int signal); - std::string get_current_time_as_string(); - void create_file_if_not_exists(const std::string& file_name); - void create_dir_if_not_exists(const std::string& dir_name); +std::string signal_to_string(int signal); +std::string get_current_time_as_string(); +void create_file_if_not_exists(const std::string &file_name); +void create_dir_if_not_exists(const std::string &dir_name); - void init_signal_config(std::set normal_quit = {SIGINT, SIGTERM}, std::set ignore_signal = {}); +void init_signal_config(std::set normal_quit = {SIGINT, SIGTERM}, + std::set ignore_signal = {}); - class String_Pool { - public: - explicit String_Pool(size_t block_size, size_t pool_size) - : block_size(block_size), pool_size(pool_size) { - grow(pool_size); - } +class String_Pool { +public: + explicit String_Pool(size_t block_size, size_t pool_size) + : block_size(block_size), pool_size(pool_size) { + grow(pool_size); + } - size_t remain_size() { - std::lock_guard g(mtx); - return strings_.size() * block_size; - } + size_t remain_size() { + std::lock_guard g(mtx); + return strings_.size() * block_size; + } - size_t free_size() { - std::lock_guard g(mtx); - return free_.size() * block_size; - } + size_t free_size() { + std::lock_guard g(mtx); + return free_.size() * block_size; + } - std::string* get() { - std::lock_guard g(mtx); + std::string *get() { + std::lock_guard g(mtx); - if (free_.empty()) { - const size_t grow_count = strings_.empty() ? std::max(pool_size, 1) : strings_.size(); + if (free_.empty()) { + const size_t grow_count = + strings_.empty() ? std::max(pool_size, 1) : strings_.size(); - std::cout << "String_Pool 扩容对象数 【" << grow_count - << "】,理论容量 【" << grow_count * block_size << "】" - << std::endl; + std::cout << "String_Pool 扩容对象数 【" << grow_count + << "】,理论容量 【" << grow_count * block_size << "】" + << std::endl; - grow(grow_count); - } + grow(grow_count); + } - std::string* ptr = free_.top(); - free_.pop(); - return ptr; - } + std::string *ptr = free_.top(); + free_.pop(); + return ptr; + } - [[nodiscard]] size_t capacity() const { - std::lock_guard g(mtx); - return strings_.size(); - } + [[nodiscard]] size_t capacity() const { + std::lock_guard g(mtx); + return strings_.size(); + } - [[nodiscard]] size_t free_count() const { - std::lock_guard g(mtx); - return free_.size(); - } + [[nodiscard]] size_t free_count() const { + std::lock_guard g(mtx); + return free_.size(); + } - private: - void grow(size_t count) { - for (size_t i = 0; i < count; ++i) { - strings_.emplace_back(); - std::string& str = strings_.back(); - str.reserve(block_size); - free_.push(&str); - } - } +private: + void grow(size_t count) { + for (size_t i = 0; i < count; ++i) { + strings_.emplace_back(); + std::string &str = strings_.back(); + str.reserve(block_size); + free_.push(&str); + } + } - void release(std::string* ptr) { - std::lock_guard g(mtx); - if (ptr) { - ptr->clear(); - free_.push(ptr); - } - } + void release(std::string *ptr) { + std::lock_guard g(mtx); + if (ptr) { + ptr->clear(); + free_.push(ptr); + } + } - void release(const std::vector& list) { - std::lock_guard g(mtx); - for (auto* li : list) { - if (li) { - li->clear(); - free_.push(li); - } - } - } + void release(const std::vector &list) { + std::lock_guard g(mtx); + for (auto *li : list) { + if (li) { + li->clear(); + free_.push(li); + } + } + } - private: - std::deque strings_; - std::stack free_{}; +private: + std::deque strings_; + std::stack free_{}; - mutable Spin_Lock mtx; + mutable Spin_Lock mtx; - size_t block_size; // 每个 std::string 预留的容量。 - size_t pool_size; // 初始创建多少个 string 对象。 + size_t block_size; // 每个 std::string 预留的容量。 + size_t pool_size; // 初始创建多少个 string 对象。 - friend struct Pool_Guard; - }; + friend struct Pool_Guard; +}; - struct Pool_Guard { - Pool_Guard(String_Pool* pool, std::string* buf) - : pool(pool), buf(buf) {} +struct Pool_Guard { + Pool_Guard(String_Pool *pool, std::string *buf) : pool(pool), buf(buf) {} - Pool_Guard(String_Pool* pool, std::vector list) - : pool(pool), list(std::move(list)) {} + Pool_Guard(String_Pool *pool, std::vector list) + : pool(pool), list(std::move(list)) {} - ~Pool_Guard() { - if (!pool) { - return; - } + ~Pool_Guard() { + if (!pool) { + return; + } - if (buf) { - pool->release(buf); - } + if (buf) { + pool->release(buf); + } - if (!list.empty()) { - pool->release(list); - } - } + if (!list.empty()) { + pool->release(list); + } + } - Pool_Guard(const Pool_Guard&) = delete; - Pool_Guard& operator=(const Pool_Guard&) = delete; + Pool_Guard(const Pool_Guard &) = delete; + Pool_Guard &operator=(const Pool_Guard &) = delete; - Pool_Guard(Pool_Guard&& other) noexcept - : pool(other.pool), - list(std::move(other.list)), - buf(other.buf) { - other.pool = nullptr; - other.buf = nullptr; - } + Pool_Guard(Pool_Guard &&other) noexcept + : pool(other.pool), list(std::move(other.list)), buf(other.buf) { + other.pool = nullptr; + other.buf = nullptr; + } - Pool_Guard& operator=(Pool_Guard&& other) noexcept { - if (this != &other) { - pool = other.pool; - list = std::move(other.list); - buf = other.buf; + Pool_Guard &operator=(Pool_Guard &&other) noexcept { + if (this != &other) { + pool = other.pool; + list = std::move(other.list); + buf = other.buf; - other.pool = nullptr; - other.buf = nullptr; - } + other.pool = nullptr; + other.buf = nullptr; + } - return *this; - } + return *this; + } - protected: - String_Pool* pool{}; - std::vector list; - std::string* buf{}; - }; +protected: + String_Pool *pool{}; + std::vector list; + std::string *buf{}; +}; - template - class Enum_Err { - public: - explicit Enum_Err(Enum_Type errc) - : nerr(errc), - native(get_error_code(), std::system_category()) {} +template class Enum_Err { +public: + explicit Enum_Err(Enum_Type errc) + : nerr(errc), native(get_error_code(), std::system_category()) {} - Enum_Err(Enum_Type errc, ERROR_CODE_TYPE code) - : nerr(errc), - native(std::error_code(code, std::system_category())) {} + Enum_Err(Enum_Type errc, ERROR_CODE_TYPE code) + : nerr(errc), native(std::error_code(code, std::system_category())) {} - Enum_Type nerr; - std::error_code native; + Enum_Type nerr; + std::error_code native; - std::string to_string() { - auto enum_name = std::string(magic_enum::template enum_type_name()); - return enum_name + "【" + Psc::to_string(nerr) + " native:" + get_error_message(native.value()) + "】"; - } - }; + std::string to_string() { + auto enum_name = + std::string(magic_enum::template enum_type_name()); + return enum_name + "【" + Psc::to_string(nerr) + + " native:" + get_error_message(native.value()) + "】"; + } +}; } // namespace Psc diff --git a/Core/system/linux.cpp b/Core/system/linux.cpp index 1ebe16d..01d6656 100644 --- a/Core/system/linux.cpp +++ b/Core/system/linux.cpp @@ -3,8 +3,8 @@ #include "export.h" #include -#include #include +#include #include #include #include @@ -41,396 +41,397 @@ namespace Psc { namespace { - std::string trim_copy(std::string value) { - auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; - value.erase(value.begin(), std::find_if(value.begin(), value.end(), not_space)); - value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), value.end()); - return value; - } - - std::string read_first_line(const std::string& file_name) { - std::ifstream in(file_name); - std::string line; - if (std::getline(in, line)) { - return trim_copy(line); - } - return ""; - } - - std::string execute_command_single(const char* cmd) { - if (!cmd || !*cmd) { - return ""; - } - - int pipefd[2]{}; - if (pipe(pipefd) != 0) { - return ""; - } - - pid_t pid = fork(); - if (pid < 0) { - close(pipefd[0]); - close(pipefd[1]); - return ""; - } - - if (pid == 0) { - close(pipefd[0]); - dup2(pipefd[1], STDOUT_FILENO); - close(pipefd[1]); - setsid(); - execl("/bin/sh", "sh", "-c", cmd, static_cast(nullptr)); - _exit(127); - } - - close(pipefd[1]); - - std::string out; - char buf[1024]; - ssize_t n = 0; - while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) { - out.append(buf, static_cast(n)); - } - close(pipefd[0]); - waitpid(pid, nullptr, 0); - return out; - } - - size_t read_proc_status_kb(const char* key) { - std::ifstream status("/proc/self/status"); - std::string line; - while (std::getline(status, line)) { - if (line.rfind(key, 0) == 0) { - size_t value_kb = 0; - if (std::sscanf(line.c_str(), "%*s %zu kB", &value_kb) == 1) { - return value_kb; - } - } - } - return 0; - } +std::string trim_copy(std::string value) { + auto not_space = [](unsigned char ch) { return !std::isspace(ch); }; + value.erase(value.begin(), + std::find_if(value.begin(), value.end(), not_space)); + value.erase(std::find_if(value.rbegin(), value.rend(), not_space).base(), + value.end()); + return value; } - std::string extract_address(const std::string& input) { - const std::regex address_regex(R"(\[([0-9a-fA-Fx]+)\])"); - std::smatch match; - if (std::regex_search(input, match, address_regex)) { - return match[1].str(); - } - return ""; +std::string read_first_line(const std::string &file_name) { + std::ifstream in(file_name); + std::string line; + if (std::getline(in, line)) { + return trim_copy(line); + } + return ""; +} + +std::string execute_command_single(const char *cmd) { + if (!cmd || !*cmd) { + return ""; + } + + int pipefd[2]{}; + if (pipe(pipefd) != 0) { + return ""; + } + + pid_t pid = fork(); + if (pid < 0) { + close(pipefd[0]); + close(pipefd[1]); + return ""; + } + + if (pid == 0) { + close(pipefd[0]); + dup2(pipefd[1], STDOUT_FILENO); + close(pipefd[1]); + setsid(); + execl("/bin/sh", "sh", "-c", cmd, static_cast(nullptr)); + _exit(127); + } + + close(pipefd[1]); + + std::string out; + char buf[1024]; + ssize_t n = 0; + while ((n = read(pipefd[0], buf, sizeof(buf))) > 0) { + out.append(buf, static_cast(n)); + } + close(pipefd[0]); + waitpid(pid, nullptr, 0); + return out; +} + +size_t read_proc_status_kb(const char *key) { + std::ifstream status("/proc/self/status"); + std::string line; + while (std::getline(status, line)) { + if (line.rfind(key, 0) == 0) { + size_t value_kb = 0; + if (std::sscanf(line.c_str(), "%*s %zu kB", &value_kb) == 1) { + return value_kb; + } } + } + return 0; +} +} // namespace - std::string execute_command(const std::string& cmd) { - FILE* fp = popen(cmd.c_str(), "r"); - if (!fp) { - return ""; - } +std::string extract_address(const std::string &input) { + const std::regex address_regex(R"(\[([0-9a-fA-Fx]+)\])"); + std::smatch match; + if (std::regex_search(input, match, address_regex)) { + return match[1].str(); + } + return ""; +} - std::string result; - char buffer[1024]; - while (fgets(buffer, sizeof(buffer), fp) != nullptr) { - result.append(buffer); - } - pclose(fp); - return result; +std::string execute_command(const std::string &cmd) { + FILE *fp = popen(cmd.c_str(), "r"); + if (!fp) { + return ""; + } + + std::string result; + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp) != nullptr) { + result.append(buffer); + } + pclose(fp); + return result; +} + +std::string get_tool(const std::string &name) { + std::string ret = name; + const std::string exe_dir = get_exe_dir(); + const std::string ret_1 = exe_dir + "/" + name; + + std::filesystem::path path = std::filesystem::u8path(exe_dir); + const auto parent = path.parent_path(); + const std::string parent_path = path_to_utf8(parent); + const std::string ret_2 = parent_path + "/lib/" + name; + + if (std::filesystem::exists(ret_1)) { + ret = ret_1; + } else if (std::filesystem::exists(ret_2)) { + ret = ret_2; + } + return ret; +} + +std::string get_stack_trace() { + std::ostringstream oss; + constexpr int max_frames = 64; + void *stack[max_frames]{}; + + const int stack_size = backtrace(stack, max_frames); + char **symbols = backtrace_symbols(stack, stack_size); + if (!symbols) { + oss << "Error retrieving stack symbols\n"; + return oss.str(); + } + + const std::string addr2line = get_tool("addr2line"); + const std::string cppfilt = get_tool("c++filt"); + const std::string exe = get_exe_path(); + + oss << "addr2line: " << addr2line << '\n'; + oss << "cppfilt: " << cppfilt << '\n'; + oss << "Stack trace: " << exe << '\n'; + + for (int i = 0; i < stack_size; ++i) { + const auto addr = reinterpret_cast(stack[i]); + oss << "【" << std::dec << std::left << std::setw(2) << i << "】"; + + char cmd[4096]; + std::snprintf(cmd, sizeof(cmd), R"(%s -e "%s" -f -i 0x%lx | %s)", + addr2line.c_str(), exe.c_str(), + static_cast(addr), cppfilt.c_str()); + + std::string str = execute_command_single(cmd); + if (str.empty() && symbols[i]) { + str = symbols[i]; } + std::replace(str.begin(), str.end(), '\n', ' '); + oss << " " << str << "【0x" << std::hex << addr << std::dec << "】" + << '\n'; + } - std::string get_tool(const std::string& name) { - std::string ret = name; - const std::string exe_dir = get_exe_dir(); - const std::string ret_1 = exe_dir + "/" + name; + free(symbols); + return oss.str(); +} - std::filesystem::path path = std::filesystem::u8path(exe_dir); - const auto parent = path.parent_path(); - const std::string parent_path = path_to_utf8(parent); - const std::string ret_2 = parent_path + "/lib/" + name; +std::string get_computer_serial_number() { + static const char *candidates[] = { + "/sys/class/dmi/id/product_serial", "/sys/class/dmi/id/board_serial", + "/sys/class/dmi/id/product_uuid", "/sys/class/dmi/id/chassis_serial"}; - if (std::filesystem::exists(ret_1)) { - ret = ret_1; - } else if (std::filesystem::exists(ret_2)) { - ret = ret_2; - } - return ret; + for (const char *file : candidates) { + std::string value = read_first_line(file); + if (!value.empty() && value != "None" && value != "Not Specified" && + value != "To Be Filled By O.E.M.") { + return value; } + } - std::string get_stack_trace() { - std::ostringstream oss; - constexpr int max_frames = 64; - void* stack[max_frames]{}; + return "Unknown"; +} - const int stack_size = backtrace(stack, max_frames); - char** symbols = backtrace_symbols(stack, stack_size); - if (!symbols) { - oss << "Error retrieving stack symbols\n"; - return oss.str(); - } +void set_current_thread_name(const std::string &name) { + std::string trimmed = + name.substr(0, 15); // Linux 线程名最多 16 字节,含结尾 \0。 + (void)pthread_setname_np(pthread_self(), trimmed.c_str()); +} - const std::string addr2line = get_tool("addr2line"); - const std::string cppfilt = get_tool("c++filt"); - const std::string exe = get_exe_path(); +void set_console_utf8() { + if (setlocale(LC_ALL, "") != nullptr) { + return; + } + if (setlocale(LC_ALL, "C.UTF-8") != nullptr) { + return; + } + (void)setlocale(LC_ALL, "en_US.UTF-8"); +} - oss << "addr2line: " << addr2line << '\n'; - oss << "cppfilt: " << cppfilt << '\n'; - oss << "Stack trace: " << exe << '\n'; +PSC_DEFINE_TRIPLE_API_FROM_BOOL(void *, load_library, PSC_LOAD_LIBRARY_PARAMS) - for (int i = 0; i < stack_size; ++i) { - const auto addr = reinterpret_cast(stack[i]); - oss << "【" << std::dec << std::left << std::setw(2) << i << "】"; +bool load_library_ec(const std::string &library_path, void *&out, + std::error_code &ec) noexcept { + out = nullptr; + ec.clear(); + (void)dlerror(); - char cmd[4096]; - std::snprintf(cmd, sizeof(cmd), - R"(%s -e "%s" -f -i 0x%lx | %s)", - addr2line.c_str(), exe.c_str(), static_cast(addr), cppfilt.c_str()); + void *library = dlopen(library_path.c_str(), RTLD_LAZY); + if (!library) { + const char *err = dlerror(); + std::cerr << library_path + << " Failed to load library: " << (err ? err : "unknown") << '\n'; + ec = std::make_error_code(std::errc::no_such_file_or_directory); + return false; + } - std::string str = execute_command_single(cmd); - if (str.empty() && symbols[i]) { - str = symbols[i]; - } - std::replace(str.begin(), str.end(), '\n', ' '); - oss << " " << str << "【0x" << std::hex << addr << std::dec << "】" << '\n'; - } + out = library; + return true; +} - free(symbols); - return oss.str(); +void *load_library_fail_fast(const std::string &library_path) { + auto ret = try_load_library(library_path); + if (!ret) { + Psc::fail_fast(); + } + return ret.value(); +} + +void free_library(void *library) { + if (library) { + dlclose(library); + } +} + +PSC_DEFINE_TRIPLE_API_FROM_BOOL(void *, load_function, PSC_LOAD_FUNCTION_PARAMS) + +bool load_function_ec(void *library, const std::string &function_name, + void *&out, std::error_code &ec) noexcept { + out = nullptr; + ec.clear(); + + if (!library) { + std::cerr << function_name << " function not loaded (library == nullptr)\n"; + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + + (void)dlerror(); + void *func = dlsym(library, function_name.c_str()); + const char *err = dlerror(); + if (err != nullptr) { + std::cerr << "dlsym failed for " << function_name << " : " << err << '\n'; + ec = std::make_error_code(std::errc::function_not_supported); + return false; + } + + out = func; + return true; +} + +void *load_function_fail_fast(void *library, const std::string &function_name) { + auto ret = try_load_function(library, function_name); + if (!ret) { + Psc::fail_fast(); + } + return ret.value(); +} + +std::string get_error_message() { + const int ec = errno; + return "错误码:" + std::to_string(ec) + ": " + std::strerror(ec); +} + +std::string get_error_message(ERROR_CODE_TYPE ec) { + return "错误码:" + std::to_string(ec) + ": " + + std::strerror(static_cast(ec)); +} + +ERROR_CODE_TYPE get_error_code() { return errno; } + +void set_error_code(ERROR_CODE_TYPE code) { errno = static_cast(code); } + +std::string get_exe_path() { + std::vector buffer(PATH_MAX + 1, '\0'); + const ssize_t len = + readlink("/proc/self/exe", buffer.data(), buffer.size() - 1); + if (len == -1) { + return ""; + } + buffer[static_cast(len)] = '\0'; + return std::string(buffer.data()); +} + +std::string get_home_dir() { + if (const char *home = std::getenv("HOME")) { + return home; + } + + struct passwd *pw = getpwuid(getuid()); + if (pw && pw->pw_dir) { + return std::string(pw->pw_dir); + } + + return ""; +} + +bool set_thread_priority(void *thread_ptr, int priority, bool realtime) { + if (!thread_ptr) { + return false; + } + + pthread_t pthread = *static_cast(thread_ptr); + int policy = realtime ? SCHED_FIFO : SCHED_OTHER; + + sched_param param{}; + if (realtime) { + const int min_prio = sched_get_priority_min(policy); + const int max_prio = sched_get_priority_max(policy); + if (min_prio >= 0 && max_prio >= min_prio) { + priority = std::max(min_prio, std::min(max_prio, priority)); } + param.sched_priority = priority; + } else { + param.sched_priority = 0; + } - std::string get_computer_serial_number() { - static const char* candidates[] = { - "/sys/class/dmi/id/product_serial", - "/sys/class/dmi/id/board_serial", - "/sys/class/dmi/id/product_uuid", - "/sys/class/dmi/id/chassis_serial" - }; + const int ret = pthread_setschedparam(pthread, policy, ¶m); + if (ret != 0) { + errno = ret; + return false; + } + return true; +} - for (const char* file : candidates) { - std::string value = read_first_line(file); - if (!value.empty() && value != "None" && value != "Not Specified" && value != "To Be Filled By O.E.M.") { - return value; - } - } +bool set_thread_priority(std::thread *thread, int priority, bool realtime) { + if (!thread) { + return false; + } - return "Unknown"; + pthread_t pthread = thread->native_handle(); + return set_thread_priority(static_cast(&pthread), priority, realtime); +} + +bool set_thread_affinity(void *thread_ptr, unsigned cpu_index) { + if (!thread_ptr) { + return false; + } + + if (cpu_index >= CPU_SETSIZE) { + errno = EINVAL; + return false; + } + + pthread_t pthread = *static_cast(thread_ptr); + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu_index, &cpuset); + + const int ret = pthread_setaffinity_np(pthread, sizeof(cpu_set_t), &cpuset); + if (ret != 0) { + errno = ret; + std::cerr << "Error setting thread affinity: " << std::strerror(ret) + << std::endl; + return false; + } + + return true; +} + +bool set_thread_affinity(std::thread *thread, unsigned cpu_index) { + if (!thread) { + return false; + } + + pthread_t pthread = thread->native_handle(); + return set_thread_affinity(static_cast(&pthread), cpu_index); +} + +std::string get_memory_info() { + auto ret = JSON::object(); + ret.append({"VmRSS (MB)", read_proc_status_kb("VmRSS:") / 1024}); + ret.append({"VmSize (MB)", read_proc_status_kb("VmSize:") / 1024}); + ret.append({"VmPeak (MB)", read_proc_status_kb("VmPeak:") / 1024}); + ret.append({"VmHWM (MB)", read_proc_status_kb("VmHWM:") / 1024}); + return ret.to_json_string(); +} + +size_t get_system_memory() { + std::ifstream meminfo("/proc/meminfo"); + std::string line; + while (std::getline(meminfo, line)) { + if (line.rfind("MemTotal:", 0) == 0) { + size_t mem_total_kb = 0; + if (std::sscanf(line.c_str(), "MemTotal: %zu kB", &mem_total_kb) == 1) { + return mem_total_kb * 1024; + } } + } + return 0; +} - void set_current_thread_name(const std::string& name) { - std::string trimmed = name.substr(0, 15); // Linux 线程名最多 16 字节,含结尾 \0。 - (void)pthread_setname_np(pthread_self(), trimmed.c_str()); - } - - void set_console_utf8() { - if (setlocale(LC_ALL, "") != nullptr) { - return; - } - if (setlocale(LC_ALL, "C.UTF-8") != nullptr) { - return; - } - (void)setlocale(LC_ALL, "en_US.UTF-8"); - } - - PSC_DEFINE_TRIPLE_API_FROM_BOOL(void*, load_library, PSC_LOAD_LIBRARY_PARAMS) - - bool load_library_ec(const std::string& library_path, void*& out, std::error_code& ec) noexcept { - out = nullptr; - ec.clear(); - (void)dlerror(); - - void* library = dlopen(library_path.c_str(), RTLD_LAZY); - if (!library) { - const char* err = dlerror(); - std::cerr << library_path << " Failed to load library: " - << (err ? err : "unknown") << '\n'; - ec = std::make_error_code(std::errc::no_such_file_or_directory); - return false; - } - - out = library; - return true; - } - - void* load_library_fail_fast(const std::string& library_path) { - auto ret = try_load_library(library_path); - if (!ret) { - Psc::fail_fast(); - } - return ret.value(); - } - - void free_library(void* library) { - if (library) { - dlclose(library); - } - } - - PSC_DEFINE_TRIPLE_API_FROM_BOOL(void*, load_function, PSC_LOAD_FUNCTION_PARAMS) - - bool load_function_ec(void* library, const std::string& function_name, void*& out, std::error_code& ec) noexcept { - out = nullptr; - ec.clear(); - - if (!library) { - std::cerr << function_name << " function not loaded (library == nullptr)\n"; - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - - (void)dlerror(); - void* func = dlsym(library, function_name.c_str()); - const char* err = dlerror(); - if (err != nullptr) { - std::cerr << "dlsym failed for " << function_name << " : " << err << '\n'; - ec = std::make_error_code(std::errc::function_not_supported); - return false; - } - - out = func; - return true; - } - - void* load_function_fail_fast(void* library, const std::string& function_name) { - auto ret = try_load_function(library, function_name); - if (!ret) { - Psc::fail_fast(); - } - return ret.value(); - } - - std::string get_error_message() { - const int ec = errno; - return "错误码:" + std::to_string(ec) + ": " + std::strerror(ec); - } - - std::string get_error_message(ERROR_CODE_TYPE ec) { - return "错误码:" + std::to_string(ec) + ": " + std::strerror(static_cast(ec)); - } - - ERROR_CODE_TYPE get_error_code() { - return errno; - } - - void set_error_code(ERROR_CODE_TYPE code) { - errno = static_cast(code); - } - - std::string get_exe_path() { - std::vector buffer(PATH_MAX + 1, '\0'); - const ssize_t len = readlink("/proc/self/exe", buffer.data(), buffer.size() - 1); - if (len == -1) { - return ""; - } - buffer[static_cast(len)] = '\0'; - return std::string(buffer.data()); - } - - std::string get_home_dir() { - if (const char* home = std::getenv("HOME")) { - return home; - } - - struct passwd* pw = getpwuid(getuid()); - if (pw && pw->pw_dir) { - return std::string(pw->pw_dir); - } - - return ""; - } - - bool set_thread_priority(void* thread_ptr, int priority, bool realtime) { - if (!thread_ptr) { - return false; - } - - pthread_t pthread = *static_cast(thread_ptr); - int policy = realtime ? SCHED_FIFO : SCHED_OTHER; - - sched_param param{}; - if (realtime) { - const int min_prio = sched_get_priority_min(policy); - const int max_prio = sched_get_priority_max(policy); - if (min_prio >= 0 && max_prio >= min_prio) { - priority = std::max(min_prio, std::min(max_prio, priority)); - } - param.sched_priority = priority; - } else { - param.sched_priority = 0; - } - - const int ret = pthread_setschedparam(pthread, policy, ¶m); - if (ret != 0) { - errno = ret; - return false; - } - return true; - } - - bool set_thread_priority(std::thread* thread, int priority, bool realtime) { - if (!thread) { - return false; - } - - pthread_t pthread = thread->native_handle(); - return set_thread_priority(static_cast(&pthread), priority, realtime); - } - - bool set_thread_affinity(void* thread_ptr, unsigned cpu_index) { - if (!thread_ptr) { - return false; - } - - if (cpu_index >= CPU_SETSIZE) { - errno = EINVAL; - return false; - } - - pthread_t pthread = *static_cast(thread_ptr); - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(cpu_index, &cpuset); - - const int ret = pthread_setaffinity_np(pthread, sizeof(cpu_set_t), &cpuset); - if (ret != 0) { - errno = ret; - std::cerr << "Error setting thread affinity: " << std::strerror(ret) << std::endl; - return false; - } - - return true; - } - - bool set_thread_affinity(std::thread* thread, unsigned cpu_index) { - if (!thread) { - return false; - } - - pthread_t pthread = thread->native_handle(); - return set_thread_affinity(static_cast(&pthread), cpu_index); - } - - std::string get_memory_info() { - auto ret = JSON::object(); - ret.append({"VmRSS (MB)", read_proc_status_kb("VmRSS:") / 1024}); - ret.append({"VmSize (MB)", read_proc_status_kb("VmSize:") / 1024}); - ret.append({"VmPeak (MB)", read_proc_status_kb("VmPeak:") / 1024}); - ret.append({"VmHWM (MB)", read_proc_status_kb("VmHWM:") / 1024}); - return ret.to_json_string(); - } - - size_t get_system_memory() { - std::ifstream meminfo("/proc/meminfo"); - std::string line; - while (std::getline(meminfo, line)) { - if (line.rfind("MemTotal:", 0) == 0) { - size_t mem_total_kb = 0; - if (std::sscanf(line.c_str(), "MemTotal: %zu kB", &mem_total_kb) == 1) { - return mem_total_kb * 1024; - } - } - } - return 0; - } - - size_t get_process_memory() { - return read_proc_status_kb("VmRSS:") * 1024; - } +size_t get_process_memory() { return read_proc_status_kb("VmRSS:") * 1024; } } // namespace Psc diff --git a/Core/system/win.cpp b/Core/system/win.cpp index 6d778ed..45943cf 100644 --- a/Core/system/win.cpp +++ b/Core/system/win.cpp @@ -24,629 +24,643 @@ #include #include - #include "../Base/global_include.h" #include "../system/export.h" #include "Core/Base/JSON.h" namespace Psc { namespace { - std::wstring utf8_to_wide_impl(const std::string& input) { - if (input.empty()) { - return L""; - } +std::wstring utf8_to_wide_impl(const std::string &input) { + if (input.empty()) { + return L""; + } - const int size = MultiByteToWideChar(CP_UTF8, 0, input.data(), static_cast(input.size()), nullptr, 0); - if (size <= 0) { - return L""; - } + const int size = MultiByteToWideChar( + CP_UTF8, 0, input.data(), static_cast(input.size()), nullptr, 0); + if (size <= 0) { + return L""; + } - std::wstring result(static_cast(size), L'\0'); - MultiByteToWideChar(CP_UTF8, 0, input.data(), static_cast(input.size()), result.data(), size); - return result; - } - - std::string wide_to_utf8_impl(const wchar_t* input, int input_len = -1) { - if (!input) { - return ""; - } - - const int size = WideCharToMultiByte(CP_UTF8, 0, input, input_len, nullptr, 0, nullptr, nullptr); - if (size <= 0) { - return ""; - } - - std::string result(static_cast(size), '\0'); - WideCharToMultiByte(CP_UTF8, 0, input, input_len, result.data(), size, nullptr, nullptr); - if (input_len == -1 && !result.empty() && result.back() == '\0') { - result.pop_back(); - } - return result; - } - - std::string wide_to_utf8_impl(const std::wstring& input) { - return wide_to_utf8_impl(input.c_str(), static_cast(input.size())); - } - - std::string codepage_to_utf8(const std::string& input, UINT codepage) { - if (input.empty()) { - return ""; - } - - const int wide_len = MultiByteToWideChar(codepage, 0, input.data(), static_cast(input.size()), nullptr, 0); - if (wide_len <= 0) { - return ""; - } - - std::wstring wide(static_cast(wide_len), L'\0'); - MultiByteToWideChar(codepage, 0, input.data(), static_cast(input.size()), wide.data(), wide_len); - return wide_to_utf8_impl(wide); - } - - std::string utf8_to_codepage(const std::string& input, UINT codepage) { - if (input.empty()) { - return ""; - } - - const std::wstring wide = utf8_to_wide_impl(input); - if (wide.empty()) { - return ""; - } - - const int len = WideCharToMultiByte(codepage, 0, wide.data(), static_cast(wide.size()), nullptr, 0, nullptr, nullptr); - if (len <= 0) { - return ""; - } - - std::string result(static_cast(len), '\0'); - WideCharToMultiByte(codepage, 0, wide.data(), static_cast(wide.size()), result.data(), len, nullptr, nullptr); - return result; - } - - std::wstring read_env_w(const wchar_t* name) { - DWORD required = GetEnvironmentVariableW(name, nullptr, 0); - if (required == 0) { - return L""; - } - - std::wstring result(required, L'\0'); - DWORD written = GetEnvironmentVariableW(name, result.data(), required); - if (written == 0) { - return L""; - } - - result.resize(written); - return result; - } - - HANDLE thread_to_win32_handle(std::thread* thread) noexcept { - if (!thread) { - return nullptr; - } - - using Native = std::thread::native_handle_type; - if constexpr (std::is_pointer::value) { - return reinterpret_cast(thread->native_handle()); - } else if constexpr (std::is_integral::value) { - return reinterpret_cast(thread->native_handle()); - } else { - // MinGW 的 libstdc++ 在某些配置下使用 winpthreads,native_handle_type 不是 Win32 HANDLE。 - return nullptr; - } - } - - struct Bstr_Guard { - explicit Bstr_Guard(const wchar_t* value) : value(SysAllocString(value)) {} - ~Bstr_Guard() { if (value) SysFreeString(value); } - Bstr_Guard(const Bstr_Guard&) = delete; - Bstr_Guard& operator=(const Bstr_Guard&) = delete; - BSTR value{}; - }; - - template - void release_com(T*& ptr) noexcept { - if (ptr) { - ptr->Release(); - ptr = nullptr; - } - } - - std::string fallback_stack_trace_without_dbghelp(void* const* stack, USHORT frames) { - std::ostringstream oss; - oss << "Stack trace addresses only; DbgHelp unavailable.\n"; - for (USHORT i = 0; i < frames; ++i) { - oss << "Frame " << std::setw(2) << i << ": " << stack[i] << '\n'; - } - return oss.str(); - } + std::wstring result(static_cast(size), L'\0'); + MultiByteToWideChar(CP_UTF8, 0, input.data(), static_cast(input.size()), + result.data(), size); + return result; } - std::string get_stack_trace() { - constexpr int max_frames = 64; - void* stack[max_frames]{}; - const USHORT frames = CaptureStackBackTrace(0, max_frames, stack, nullptr); +std::string wide_to_utf8_impl(const wchar_t *input, int input_len = -1) { + if (!input) { + return ""; + } - HMODULE dbghelp = LoadLibraryW(L"DbgHelp.dll"); - if (!dbghelp) { - return fallback_stack_trace_without_dbghelp(stack, frames); - } + const int size = WideCharToMultiByte(CP_UTF8, 0, input, input_len, nullptr, 0, + nullptr, nullptr); + if (size <= 0) { + return ""; + } - using SymInitializeT = BOOL(WINAPI*)(HANDLE, PCSTR, BOOL); - using SymSetOptionsT = DWORD(WINAPI*)(DWORD); - using SymFromAddrT = BOOL(WINAPI*)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); - using SymGetLineFromAddr64T = BOOL(WINAPI*)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); - using SymCleanupT = BOOL(WINAPI*)(HANDLE); + std::string result(static_cast(size), '\0'); + WideCharToMultiByte(CP_UTF8, 0, input, input_len, result.data(), size, + nullptr, nullptr); + if (input_len == -1 && !result.empty() && result.back() == '\0') { + result.pop_back(); + } + return result; +} - auto pSymInitialize = reinterpret_cast(GetProcAddress(dbghelp, "SymInitialize")); - auto pSymSetOptions = reinterpret_cast(GetProcAddress(dbghelp, "SymSetOptions")); - auto pSymFromAddr = reinterpret_cast(GetProcAddress(dbghelp, "SymFromAddr")); - auto pSymGetLineFromAddr64 = reinterpret_cast(GetProcAddress(dbghelp, "SymGetLineFromAddr64")); - auto pSymCleanup = reinterpret_cast(GetProcAddress(dbghelp, "SymCleanup")); +std::string wide_to_utf8_impl(const std::wstring &input) { + return wide_to_utf8_impl(input.c_str(), static_cast(input.size())); +} - if (!pSymInitialize || !pSymSetOptions || !pSymFromAddr || !pSymGetLineFromAddr64) { - FreeLibrary(dbghelp); - return fallback_stack_trace_without_dbghelp(stack, frames); - } +std::string codepage_to_utf8(const std::string &input, UINT codepage) { + if (input.empty()) { + return ""; + } - HANDLE process = GetCurrentProcess(); - std::ostringstream oss; + const int wide_len = MultiByteToWideChar( + codepage, 0, input.data(), static_cast(input.size()), nullptr, 0); + if (wide_len <= 0) { + return ""; + } - if (!pSymInitialize(process, nullptr, TRUE)) { - FreeLibrary(dbghelp); - return fallback_stack_trace_without_dbghelp(stack, frames); - } + std::wstring wide(static_cast(wide_len), L'\0'); + MultiByteToWideChar(codepage, 0, input.data(), static_cast(input.size()), + wide.data(), wide_len); + return wide_to_utf8_impl(wide); +} - pSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); +std::string utf8_to_codepage(const std::string &input, UINT codepage) { + if (input.empty()) { + return ""; + } - constexpr DWORD max_name_len = MAX_SYM_NAME; - std::vector symbol_buffer(sizeof(SYMBOL_INFO) + max_name_len * sizeof(char)); - auto* symbol = reinterpret_cast(symbol_buffer.data()); - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - symbol->MaxNameLen = max_name_len; + const std::wstring wide = utf8_to_wide_impl(input); + if (wide.empty()) { + return ""; + } - for (USHORT i = 0; i < frames; ++i) { - DWORD64 address = reinterpret_cast(stack[i]); - DWORD64 displacement64 = 0; + const int len = WideCharToMultiByte(codepage, 0, wide.data(), + static_cast(wide.size()), nullptr, 0, + nullptr, nullptr); + if (len <= 0) { + return ""; + } - oss << "Frame " << std::right << std::setw(2) << i << ": "; + std::string result(static_cast(len), '\0'); + WideCharToMultiByte(codepage, 0, wide.data(), static_cast(wide.size()), + result.data(), len, nullptr, nullptr); + return result; +} - if (pSymFromAddr(process, address, &displacement64, symbol)) { - oss << std::left << std::setw(30) << symbol->Name << " "; - } else { - oss << std::left << std::setw(30) << "" << " "; - } +std::wstring read_env_w(const wchar_t *name) { + DWORD required = GetEnvironmentVariableW(name, nullptr, 0); + if (required == 0) { + return L""; + } - IMAGEHLP_LINE64 line{}; - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - DWORD displacement = 0; - if (pSymGetLineFromAddr64(process, address, &displacement, &line)) { - oss << line.FileName << ':' << line.LineNumber << " at 0x" << std::hex << address << std::dec << '\n'; - } else { - oss << "at 0x" << std::hex << address << std::dec << '\n'; - } - } + std::wstring result(required, L'\0'); + DWORD written = GetEnvironmentVariableW(name, result.data(), required); + if (written == 0) { + return L""; + } - if (pSymCleanup) { - pSymCleanup(process); - } - FreeLibrary(dbghelp); - return oss.str(); + result.resize(written); + return result; +} + +HANDLE thread_to_win32_handle(std::thread *thread) noexcept { + if (!thread) { + return nullptr; + } + + using Native = std::thread::native_handle_type; + if constexpr (std::is_pointer::value) { + return reinterpret_cast(thread->native_handle()); + } else if constexpr (std::is_integral::value) { + return reinterpret_cast(thread->native_handle()); + } else { + // MinGW 的 libstdc++ 在某些配置下使用 winpthreads,native_handle_type 不是 + // Win32 HANDLE。 + return nullptr; + } +} + +struct Bstr_Guard { + explicit Bstr_Guard(const wchar_t *value) : value(SysAllocString(value)) {} + ~Bstr_Guard() { + if (value) + SysFreeString(value); + } + Bstr_Guard(const Bstr_Guard &) = delete; + Bstr_Guard &operator=(const Bstr_Guard &) = delete; + BSTR value{}; +}; + +template void release_com(T *&ptr) noexcept { + if (ptr) { + ptr->Release(); + ptr = nullptr; + } +} + +std::string fallback_stack_trace_without_dbghelp(void *const *stack, + USHORT frames) { + std::ostringstream oss; + oss << "Stack trace addresses only; DbgHelp unavailable.\n"; + for (USHORT i = 0; i < frames; ++i) { + oss << "Frame " << std::setw(2) << i << ": " << stack[i] << '\n'; + } + return oss.str(); +} +} // namespace + +std::string get_stack_trace() { + constexpr int max_frames = 64; + void *stack[max_frames]{}; + const USHORT frames = CaptureStackBackTrace(0, max_frames, stack, nullptr); + + HMODULE dbghelp = LoadLibraryW(L"DbgHelp.dll"); + if (!dbghelp) { + return fallback_stack_trace_without_dbghelp(stack, frames); + } + + using SymInitializeT = BOOL(WINAPI *)(HANDLE, PCSTR, BOOL); + using SymSetOptionsT = DWORD(WINAPI *)(DWORD); + using SymFromAddrT = BOOL(WINAPI *)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO); + using SymGetLineFromAddr64T = + BOOL(WINAPI *)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); + using SymCleanupT = BOOL(WINAPI *)(HANDLE); + + auto pSymInitialize = reinterpret_cast( + GetProcAddress(dbghelp, "SymInitialize")); + auto pSymSetOptions = reinterpret_cast( + GetProcAddress(dbghelp, "SymSetOptions")); + auto pSymFromAddr = + reinterpret_cast(GetProcAddress(dbghelp, "SymFromAddr")); + auto pSymGetLineFromAddr64 = reinterpret_cast( + GetProcAddress(dbghelp, "SymGetLineFromAddr64")); + auto pSymCleanup = + reinterpret_cast(GetProcAddress(dbghelp, "SymCleanup")); + + if (!pSymInitialize || !pSymSetOptions || !pSymFromAddr || + !pSymGetLineFromAddr64) { + FreeLibrary(dbghelp); + return fallback_stack_trace_without_dbghelp(stack, frames); + } + + HANDLE process = GetCurrentProcess(); + std::ostringstream oss; + + if (!pSymInitialize(process, nullptr, TRUE)) { + FreeLibrary(dbghelp); + return fallback_stack_trace_without_dbghelp(stack, frames); + } + + pSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + + constexpr DWORD max_name_len = MAX_SYM_NAME; + std::vector symbol_buffer(sizeof(SYMBOL_INFO) + + max_name_len * sizeof(char)); + auto *symbol = reinterpret_cast(symbol_buffer.data()); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = max_name_len; + + for (USHORT i = 0; i < frames; ++i) { + DWORD64 address = reinterpret_cast(stack[i]); + DWORD64 displacement64 = 0; + + oss << "Frame " << std::right << std::setw(2) << i << ": "; + + if (pSymFromAddr(process, address, &displacement64, symbol)) { + oss << std::left << std::setw(30) << symbol->Name << " "; + } else { + oss << std::left << std::setw(30) << "" << " "; } - void set_current_thread_name(const std::string& name) { - const std::wstring wname = utf8_to_wide_impl(name); - if (wname.empty()) { - return; - } + IMAGEHLP_LINE64 line{}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + DWORD displacement = 0; + if (pSymGetLineFromAddr64(process, address, &displacement, &line)) { + oss << line.FileName << ':' << line.LineNumber << " at 0x" << std::hex + << address << std::dec << '\n'; + } else { + oss << "at 0x" << std::hex << address << std::dec << '\n'; + } + } - using SetThreadDescriptionT = HRESULT(WINAPI*)(HANDLE, PCWSTR); - HMODULE kernel32 = GetModuleHandleW(L"Kernel32.dll"); - auto pSetThreadDescription = kernel32 - ? reinterpret_cast(GetProcAddress(kernel32, "SetThreadDescription")) - : nullptr; + if (pSymCleanup) { + pSymCleanup(process); + } + FreeLibrary(dbghelp); + return oss.str(); +} - if (pSetThreadDescription) { - (void)pSetThreadDescription(GetCurrentThread(), wname.c_str()); - } +void set_current_thread_name(const std::string &name) { + const std::wstring wname = utf8_to_wide_impl(name); + if (wname.empty()) { + return; + } + + using SetThreadDescriptionT = HRESULT(WINAPI *)(HANDLE, PCWSTR); + HMODULE kernel32 = GetModuleHandleW(L"Kernel32.dll"); + auto pSetThreadDescription = + kernel32 ? reinterpret_cast( + GetProcAddress(kernel32, "SetThreadDescription")) + : nullptr; + + if (pSetThreadDescription) { + (void)pSetThreadDescription(GetCurrentThread(), wname.c_str()); + } +} + +void set_console_utf8() { + (void)SetConsoleOutputCP(CP_UTF8); + (void)SetConsoleCP(CP_UTF8); +} + +PSC_DEFINE_TRIPLE_API_FROM_BOOL(void *, load_library, PSC_LOAD_LIBRARY_PARAMS) + +bool load_library_ec(const std::string &library_path, void *&out, + std::error_code &ec) noexcept { + out = nullptr; + ec.clear(); + + if (library_path.empty()) { + ec = std::make_error_code(std::errc::invalid_argument); + return false; + } + + const std::wstring wpath = utf8_to_wide_impl(library_path); + HMODULE h = LoadLibraryW(wpath.c_str()); + if (!h) { + ec = std::error_code(static_cast(GetLastError()), + std::system_category()); + std::cerr << "加载库失败:【" << library_path << "】 " << ec.message() + << " (code=" << ec.value() << ")\n"; + return false; + } + + out = reinterpret_cast(h); + return true; +} + +void *load_library_fail_fast(const std::string &library_path) { + auto ret = try_load_library(library_path); + if (!ret) { + Psc::fail_fast(); + } + return ret.value(); +} + +void free_library(void *library) { + if (library) { + FreeLibrary(reinterpret_cast(library)); + } +} + +PSC_DEFINE_TRIPLE_API_FROM_BOOL(void *, load_function, PSC_LOAD_FUNCTION_PARAMS) + +bool load_function_ec(void *library, const std::string &function_name, + void *&out, std::error_code &ec) noexcept { + out = nullptr; + ec.clear(); + + if (!library) { + ec = std::make_error_code(std::errc::invalid_argument); + std::cerr << "load_function: " << function_name + << " but library == nullptr\n"; + return false; + } + + FARPROC p = + GetProcAddress(reinterpret_cast(library), function_name.c_str()); + if (!p) { + ec = std::error_code(static_cast(GetLastError()), + std::system_category()); + std::cerr << "Failed to get function pointer for: " << function_name + << " : " << ec.message() << " (code=" << ec.value() << ")\n"; + return false; + } + + out = reinterpret_cast(p); + return true; +} + +void *load_function_fail_fast(void *library, const std::string &function_name) { + auto ret = try_load_function(library, function_name); + if (!ret) { + Psc::fail_fast(); + } + return ret.value(); +} + +std::string get_computer_serial_number() { + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + const bool need_uninit = SUCCEEDED(hr); + if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) { + return ""; + } + + hr = CoInitializeSecurity( + nullptr, -1, nullptr, nullptr, RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE, nullptr); + if (FAILED(hr) && hr != RPC_E_TOO_LATE) { + if (need_uninit) { + CoUninitialize(); + } + return ""; + } + + IWbemLocator *locator = nullptr; + IWbemServices *services = nullptr; + IEnumWbemClassObject *enumerator = nullptr; + IWbemClassObject *object = nullptr; + std::string result; + + hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, + IID_IWbemLocator, reinterpret_cast(&locator)); + if (FAILED(hr) || !locator) { + if (need_uninit) + CoUninitialize(); + return ""; + } + + Bstr_Guard ns(L"ROOT\\CIMV2"); + hr = locator->ConnectServer(ns.value, nullptr, nullptr, nullptr, 0, nullptr, + nullptr, &services); + if (SUCCEEDED(hr) && services) { + hr = CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, + nullptr, RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE); + } + + if (SUCCEEDED(hr) && services) { + Bstr_Guard lang(L"WQL"); + Bstr_Guard query(L"SELECT SerialNumber FROM Win32_BIOS"); + hr = services->ExecQuery(lang.value, query.value, + WBEM_FLAG_FORWARD_ONLY | + WBEM_FLAG_RETURN_IMMEDIATELY, + nullptr, &enumerator); + } + + if (SUCCEEDED(hr) && enumerator) { + ULONG returned = 0; + hr = enumerator->Next(WBEM_INFINITE, 1, &object, &returned); + if (SUCCEEDED(hr) && returned > 0 && object) { + VARIANT vtSerial; + VariantInit(&vtSerial); + hr = object->Get(L"SerialNumber", 0, &vtSerial, nullptr, nullptr); + if (SUCCEEDED(hr) && vtSerial.vt == VT_BSTR && vtSerial.bstrVal) { + result = wide_to_utf8_impl(vtSerial.bstrVal); + } + VariantClear(&vtSerial); + } + } + + release_com(object); + release_com(enumerator); + release_com(services); + release_com(locator); + if (need_uninit) { + CoUninitialize(); + } + return result; +} + +std::string error_code_to_string(DWORD error_code) { + wchar_t *message = nullptr; + DWORD size = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&message), 0, nullptr); + + std::string result = "错误码:" + std::to_string(error_code) + ": "; + if (size > 0 && message) { + result += wide_to_utf8_impl(message, static_cast(size)); + LocalFree(message); + } else { + result += "获取错误信息失败"; + } + return result; +} + +std::string get_error_message() { return error_code_to_string(GetLastError()); } + +std::string get_error_message(ERROR_CODE_TYPE code) { + return error_code_to_string(static_cast(code)); +} + +ERROR_CODE_TYPE get_error_code() { + return static_cast(GetLastError()); +} + +void set_error_code(ERROR_CODE_TYPE code) { + SetLastError(static_cast(code)); +} + +std::string to_upper_case(const std::string &input) { + std::string result = input; + for (char &ch : result) { + ch = static_cast(std::toupper(static_cast(ch))); + } + return result; +} + +std::string get_home_dir() { + std::wstring home = read_env_w(L"USERPROFILE"); + if (home.empty()) { + std::wstring drive = read_env_w(L"HOMEDRIVE"); + std::wstring path = read_env_w(L"HOMEPATH"); + home = drive + path; + } + std::string result = wide_to_utf8_impl(home); + std::replace(result.begin(), result.end(), '\\', '/'); + return result; +} + +std::string get_exe_path() { + std::wstring buffer(MAX_PATH, L'\0'); + + for (;;) { + DWORD len = GetModuleFileNameW(nullptr, buffer.data(), + static_cast(buffer.size())); + if (len == 0) { + return ""; } - void set_console_utf8() { - (void)SetConsoleOutputCP(CP_UTF8); - (void)SetConsoleCP(CP_UTF8); + if (len < buffer.size() - 1) { + buffer.resize(len); + break; } - PSC_DEFINE_TRIPLE_API_FROM_BOOL(void*, load_library, PSC_LOAD_LIBRARY_PARAMS) - - bool load_library_ec(const std::string& library_path, void*& out, std::error_code& ec) noexcept { - out = nullptr; - ec.clear(); - - if (library_path.empty()) { - ec = std::make_error_code(std::errc::invalid_argument); - return false; - } - - const std::wstring wpath = utf8_to_wide_impl(library_path); - HMODULE h = LoadLibraryW(wpath.c_str()); - if (!h) { - ec = std::error_code(static_cast(GetLastError()), std::system_category()); - std::cerr << "加载库失败:【" << library_path << "】 " - << ec.message() << " (code=" << ec.value() << ")\n"; - return false; - } - - out = reinterpret_cast(h); - return true; + buffer.resize(buffer.size() * 2); + if (buffer.size() > 32768) { + return ""; } + } - void* load_library_fail_fast(const std::string& library_path) { - auto ret = try_load_library(library_path); - if (!ret) { - Psc::fail_fast(); - } - return ret.value(); + std::string result = wide_to_utf8_impl(buffer); + std::replace(result.begin(), result.end(), '\\', '/'); + return result; +} + +std::string utf8_to_gbk(const std::string &utf8Str) { + return utf8_to_codepage(utf8Str, CP_ACP); +} + +std::string gbk_to_utf8(const std::string &gbkStr) { + return codepage_to_utf8(gbkStr, CP_ACP); +} + +bool set_thread_priority(std::thread *thread, int priority, bool realtime) { + HANDLE hThread = thread_to_win32_handle(thread); + if (!hThread) { + return false; + } + return set_thread_priority(reinterpret_cast(hThread), priority, + realtime); +} + +bool set_thread_priority(void *thread_ptr, int priority, bool realtime) { + HANDLE hThread = static_cast(thread_ptr); + if (!hThread) { + return false; + } + + if (realtime) { + if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) { + return false; } + return SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL) != 0; + } - void free_library(void* library) { - if (library) { - FreeLibrary(reinterpret_cast(library)); - } - } + if (priority < THREAD_PRIORITY_IDLE) { + priority = THREAD_PRIORITY_IDLE; + } + if (priority > THREAD_PRIORITY_TIME_CRITICAL) { + priority = THREAD_PRIORITY_TIME_CRITICAL; + } - PSC_DEFINE_TRIPLE_API_FROM_BOOL(void*, load_function, PSC_LOAD_FUNCTION_PARAMS) + return SetThreadPriority(hThread, priority) != 0; +} - bool load_function_ec(void* library, const std::string& function_name, void*& out, std::error_code& ec) noexcept { - out = nullptr; - ec.clear(); +bool set_thread_affinity(void *thread_ptr, unsigned cpu_index) { + HANDLE hThread = static_cast(thread_ptr); + if (!hThread) { + return false; + } - if (!library) { - ec = std::make_error_code(std::errc::invalid_argument); - std::cerr << "load_function: " << function_name << " but library == nullptr\n"; - return false; - } + const unsigned max_bits = sizeof(DWORD_PTR) * 8; + if (cpu_index >= max_bits) { + return false; + } - FARPROC p = GetProcAddress(reinterpret_cast(library), function_name.c_str()); - if (!p) { - ec = std::error_code(static_cast(GetLastError()), std::system_category()); - std::cerr << "Failed to get function pointer for: " << function_name - << " : " << ec.message() << " (code=" << ec.value() << ")\n"; - return false; - } + DWORD_PTR mask = (static_cast(1) << cpu_index); + return SetThreadAffinityMask(hThread, mask) != 0; +} - out = reinterpret_cast(p); - return true; - } +bool set_thread_affinity(std::thread *thread, unsigned cpu_index) { + HANDLE hThread = thread_to_win32_handle(thread); + if (!hThread) { + return false; + } + return set_thread_affinity(reinterpret_cast(hThread), cpu_index); +} - void* load_function_fail_fast(void* library, const std::string& function_name) { - auto ret = try_load_function(library, function_name); - if (!ret) { - Psc::fail_fast(); - } - return ret.value(); - } +size_t get_system_memory() { + MEMORYSTATUSEX memStatus{}; + memStatus.dwLength = sizeof(MEMORYSTATUSEX); + if (GlobalMemoryStatusEx(&memStatus)) { + return static_cast(memStatus.ullTotalPhys); + } + return 0; +} - std::string get_computer_serial_number() { - HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - const bool need_uninit = SUCCEEDED(hr); - if (FAILED(hr) && hr != RPC_E_CHANGED_MODE) { - return ""; - } +size_t get_process_memory() { + PROCESS_MEMORY_COUNTERS memCounter{}; + if (GetProcessMemoryInfo(GetCurrentProcess(), &memCounter, + sizeof(memCounter))) { + return static_cast(memCounter.WorkingSetSize); + } + return 0; +} - hr = CoInitializeSecurity(nullptr, -1, nullptr, nullptr, - RPC_C_AUTHN_LEVEL_DEFAULT, - RPC_C_IMP_LEVEL_IMPERSONATE, - nullptr, EOAC_NONE, nullptr); - if (FAILED(hr) && hr != RPC_E_TOO_LATE) { - if (need_uninit) { - CoUninitialize(); - } - return ""; - } +std::string get_memory_info() { + MEMORYSTATUSEX status{}; + status.dwLength = sizeof(status); + if (!GlobalMemoryStatusEx(&status)) { + return "Failed to get memory status"; + } - IWbemLocator* locator = nullptr; - IWbemServices* services = nullptr; - IEnumWbemClassObject* enumerator = nullptr; - IWbemClassObject* object = nullptr; - std::string result; + auto ret = JSON::object(); + ret.append( + {"Total physical memory (MB)", status.ullTotalPhys / (1024 * 1024)}); + ret.append( + {"Available physical memory (MB)", status.ullAvailPhys / (1024 * 1024)}); + ret.append( + {"Total virtual memory (MB)", status.ullTotalVirtual / (1024 * 1024)}); + ret.append({"Available virtual memory (MB)", + status.ullAvailVirtual / (1024 * 1024)}); + ret.append({"Total page file (MB)", status.ullTotalPageFile / (1024 * 1024)}); + ret.append( + {"Available page file (MB)", status.ullAvailPageFile / (1024 * 1024)}); + return ret.to_json_string(); +} - hr = CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER, - IID_IWbemLocator, reinterpret_cast(&locator)); - if (FAILED(hr) || !locator) { - if (need_uninit) CoUninitialize(); - return ""; - } +int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers) { + using MiniDumpWriteDumpT = BOOL(WINAPI *)( + HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION); - Bstr_Guard ns(L"ROOT\\CIMV2"); - hr = locator->ConnectServer(ns.value, nullptr, nullptr, nullptr, 0, nullptr, nullptr, &services); - if (SUCCEEDED(hr) && services) { - hr = CoSetProxyBlanket(services, - RPC_C_AUTHN_WINNT, - RPC_C_AUTHZ_NONE, - nullptr, - RPC_C_AUTHN_LEVEL_CALL, - RPC_C_IMP_LEVEL_IMPERSONATE, - nullptr, - EOAC_NONE); - } + HMODULE hDbgHelp = LoadLibraryW(L"DbgHelp.dll"); + if (!hDbgHelp) { + return EXCEPTION_CONTINUE_EXECUTION; + } - if (SUCCEEDED(hr) && services) { - Bstr_Guard lang(L"WQL"); - Bstr_Guard query(L"SELECT SerialNumber FROM Win32_BIOS"); - hr = services->ExecQuery(lang.value, query.value, - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - nullptr, &enumerator); - } + auto pfnMiniDumpWriteDump = reinterpret_cast( + GetProcAddress(hDbgHelp, "MiniDumpWriteDump")); + if (!pfnMiniDumpWriteDump) { + FreeLibrary(hDbgHelp); + return EXCEPTION_CONTINUE_EXECUTION; + } - if (SUCCEEDED(hr) && enumerator) { - ULONG returned = 0; - hr = enumerator->Next(WBEM_INFINITE, 1, &object, &returned); - if (SUCCEEDED(hr) && returned > 0 && object) { - VARIANT vtSerial; - VariantInit(&vtSerial); - hr = object->Get(L"SerialNumber", 0, &vtSerial, nullptr, nullptr); - if (SUCCEEDED(hr) && vtSerial.vt == VT_BSTR && vtSerial.bstrVal) { - result = wide_to_utf8_impl(vtSerial.bstrVal); - } - VariantClear(&vtSerial); - } - } + wchar_t fileName[MAX_PATH]{}; + SYSTEMTIME localTime{}; + GetLocalTime(&localTime); + std::swprintf(fileName, MAX_PATH, + L"DumpDemo_v1.0-%04u%02u%02u-%02u%02u%02u.dmp", localTime.wYear, + localTime.wMonth, localTime.wDay, localTime.wHour, + localTime.wMinute, localTime.wSecond); - release_com(object); - release_com(enumerator); - release_com(services); - release_com(locator); - if (need_uninit) { - CoUninitialize(); - } - return result; - } + HANDLE hDumpFile = CreateFileW(fileName, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, nullptr, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hDumpFile == INVALID_HANDLE_VALUE) { + FreeLibrary(hDbgHelp); + return EXCEPTION_CONTINUE_EXECUTION; + } - std::string error_code_to_string(DWORD error_code) { - wchar_t* message = nullptr; - DWORD size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - error_code, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(&message), - 0, - nullptr); + MINIDUMP_EXCEPTION_INFORMATION expParam{}; + expParam.ThreadId = GetCurrentThreadId(); + expParam.ExceptionPointers = pExceptionPointers; + expParam.ClientPointers = FALSE; - std::string result = "错误码:" + std::to_string(error_code) + ": "; - if (size > 0 && message) { - result += wide_to_utf8_impl(message, static_cast(size)); - LocalFree(message); - } else { - result += "获取错误信息失败"; - } - return result; - } + pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, + MiniDumpWithDataSegs, + pExceptionPointers ? &expParam : nullptr, nullptr, + nullptr); - std::string get_error_message() { - return error_code_to_string(GetLastError()); - } + CloseHandle(hDumpFile); + FreeLibrary(hDbgHelp); + return EXCEPTION_EXECUTE_HANDLER; +} - std::string get_error_message(ERROR_CODE_TYPE code) { - return error_code_to_string(static_cast(code)); - } - - ERROR_CODE_TYPE get_error_code() { - return static_cast(GetLastError()); - } - - void set_error_code(ERROR_CODE_TYPE code) { - SetLastError(static_cast(code)); - } - - std::string to_upper_case(const std::string& input) { - std::string result = input; - for (char& ch : result) { - ch = static_cast(std::toupper(static_cast(ch))); - } - return result; - } - - std::string get_home_dir() { - std::wstring home = read_env_w(L"USERPROFILE"); - if (home.empty()) { - std::wstring drive = read_env_w(L"HOMEDRIVE"); - std::wstring path = read_env_w(L"HOMEPATH"); - home = drive + path; - } - std::string result = wide_to_utf8_impl(home); - std::replace(result.begin(), result.end(), '\\', '/'); - return result; - } - - std::string get_exe_path() { - std::wstring buffer(MAX_PATH, L'\0'); - - for (;;) { - DWORD len = GetModuleFileNameW(nullptr, buffer.data(), static_cast(buffer.size())); - if (len == 0) { - return ""; - } - - if (len < buffer.size() - 1) { - buffer.resize(len); - break; - } - - buffer.resize(buffer.size() * 2); - if (buffer.size() > 32768) { - return ""; - } - } - - std::string result = wide_to_utf8_impl(buffer); - std::replace(result.begin(), result.end(), '\\', '/'); - return result; - } - - std::string utf8_to_gbk(const std::string& utf8Str) { - return utf8_to_codepage(utf8Str, CP_ACP); - } - - std::string gbk_to_utf8(const std::string& gbkStr) { - return codepage_to_utf8(gbkStr, CP_ACP); - } - - bool set_thread_priority(std::thread* thread, int priority, bool realtime) { - HANDLE hThread = thread_to_win32_handle(thread); - if (!hThread) { - return false; - } - return set_thread_priority(reinterpret_cast(hThread), priority, realtime); - } - - bool set_thread_priority(void* thread_ptr, int priority, bool realtime) { - HANDLE hThread = static_cast(thread_ptr); - if (!hThread) { - return false; - } - - if (realtime) { - if (!SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) { - return false; - } - return SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL) != 0; - } - - if (priority < THREAD_PRIORITY_IDLE) { - priority = THREAD_PRIORITY_IDLE; - } - if (priority > THREAD_PRIORITY_TIME_CRITICAL) { - priority = THREAD_PRIORITY_TIME_CRITICAL; - } - - return SetThreadPriority(hThread, priority) != 0; - } - - bool set_thread_affinity(void* thread_ptr, unsigned cpu_index) { - HANDLE hThread = static_cast(thread_ptr); - if (!hThread) { - return false; - } - - const unsigned max_bits = sizeof(DWORD_PTR) * 8; - if (cpu_index >= max_bits) { - return false; - } - - DWORD_PTR mask = (static_cast(1) << cpu_index); - return SetThreadAffinityMask(hThread, mask) != 0; - } - - bool set_thread_affinity(std::thread* thread, unsigned cpu_index) { - HANDLE hThread = thread_to_win32_handle(thread); - if (!hThread) { - return false; - } - return set_thread_affinity(reinterpret_cast(hThread), cpu_index); - } - - size_t get_system_memory() { - MEMORYSTATUSEX memStatus{}; - memStatus.dwLength = sizeof(MEMORYSTATUSEX); - if (GlobalMemoryStatusEx(&memStatus)) { - return static_cast(memStatus.ullTotalPhys); - } - return 0; - } - - size_t get_process_memory() { - PROCESS_MEMORY_COUNTERS memCounter{}; - if (GetProcessMemoryInfo(GetCurrentProcess(), &memCounter, sizeof(memCounter))) { - return static_cast(memCounter.WorkingSetSize); - } - return 0; - } - - std::string get_memory_info() { - MEMORYSTATUSEX status{}; - status.dwLength = sizeof(status); - if (!GlobalMemoryStatusEx(&status)) { - return "Failed to get memory status"; - } - - auto ret = JSON::object(); - ret.append({"Total physical memory (MB)", status.ullTotalPhys / (1024 * 1024)}); - ret.append({"Available physical memory (MB)", status.ullAvailPhys / (1024 * 1024)}); - ret.append({"Total virtual memory (MB)", status.ullTotalVirtual / (1024 * 1024)}); - ret.append({"Available virtual memory (MB)", status.ullAvailVirtual / (1024 * 1024)}); - ret.append({"Total page file (MB)", status.ullTotalPageFile / (1024 * 1024)}); - ret.append({"Available page file (MB)", status.ullAvailPageFile / (1024 * 1024)}); - return ret.to_json_string(); - } - - int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers) { - using MiniDumpWriteDumpT = BOOL(WINAPI*)(HANDLE, - DWORD, - HANDLE, - MINIDUMP_TYPE, - PMINIDUMP_EXCEPTION_INFORMATION, - PMINIDUMP_USER_STREAM_INFORMATION, - PMINIDUMP_CALLBACK_INFORMATION); - - HMODULE hDbgHelp = LoadLibraryW(L"DbgHelp.dll"); - if (!hDbgHelp) { - return EXCEPTION_CONTINUE_EXECUTION; - } - - auto pfnMiniDumpWriteDump = reinterpret_cast(GetProcAddress(hDbgHelp, "MiniDumpWriteDump")); - if (!pfnMiniDumpWriteDump) { - FreeLibrary(hDbgHelp); - return EXCEPTION_CONTINUE_EXECUTION; - } - - wchar_t fileName[MAX_PATH]{}; - SYSTEMTIME localTime{}; - GetLocalTime(&localTime); - std::swprintf(fileName, MAX_PATH, L"DumpDemo_v1.0-%04u%02u%02u-%02u%02u%02u.dmp", - localTime.wYear, - localTime.wMonth, - localTime.wDay, - localTime.wHour, - localTime.wMinute, - localTime.wSecond); - - HANDLE hDumpFile = CreateFileW(fileName, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE | FILE_SHARE_READ, - nullptr, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - nullptr); - if (hDumpFile == INVALID_HANDLE_VALUE) { - FreeLibrary(hDbgHelp); - return EXCEPTION_CONTINUE_EXECUTION; - } - - MINIDUMP_EXCEPTION_INFORMATION expParam{}; - expParam.ThreadId = GetCurrentThreadId(); - expParam.ExceptionPointers = pExceptionPointers; - expParam.ClientPointers = FALSE; - - pfnMiniDumpWriteDump(GetCurrentProcess(), - GetCurrentProcessId(), - hDumpFile, - MiniDumpWithDataSegs, - pExceptionPointers ? &expParam : nullptr, - nullptr, - nullptr); - - CloseHandle(hDumpFile); - FreeLibrary(hDbgHelp); - return EXCEPTION_EXECUTE_HANDLER; - } - - LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo) { - if (IsDebuggerPresent()) { - return EXCEPTION_CONTINUE_SEARCH; - } - return GenerateMiniDump(lpExceptionInfo); - } +LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo) { + if (IsDebuggerPresent()) { + return EXCEPTION_CONTINUE_SEARCH; + } + return GenerateMiniDump(lpExceptionInfo); +} } // namespace Psc diff --git a/Core/transmit_protocol/Channel_Simulator/Channel_Simulator.cpp b/Core/transmit_protocol/Channel_Simulator/Channel_Simulator.cpp index 1a5e0d0..bcb69d2 100644 --- a/Core/transmit_protocol/Channel_Simulator/Channel_Simulator.cpp +++ b/Core/transmit_protocol/Channel_Simulator/Channel_Simulator.cpp @@ -1,14 +1,15 @@ #include "Channel_Simulator.h" #include - namespace Psc { // 创建数据包长度的随机序列,长度在 [min, max] 范围内,确保总长度为 total_length -std::vector create_order_vec(Len_Type total_length, Len_Type min, Len_Type max) { +std::vector create_order_vec(Len_Type total_length, Len_Type min, + Len_Type max) { std::vector lengths; - std::mt19937 rng(time(0)); // 随机数生成器 - std::uniform_int_distribution dist(min, max); // 生成每个数据包的长度的随机范围 + std::mt19937 rng(time(0)); // 随机数生成器 + std::uniform_int_distribution dist( + min, max); // 生成每个数据包的长度的随机范围 Len_Type current_length = 0; @@ -45,7 +46,7 @@ std::vector create_order_vec(Len_Type total_length, Len_Type min, Len_ if (len < min || len > max) { printf("Error: Packet length out of range (%d)\n", len); exit(-1); - return {}; // 返回空向量,表示生成的数据包不符合条件 + return {}; // 返回空向量,表示生成的数据包不符合条件 } } @@ -56,9 +57,10 @@ std::vector create_order_vec(Len_Type total_length, Len_Type min, Len_ } if (total_sum != total_length) { - printf("Error: Total length mismatch (%d != %d)\n", total_sum, total_length); + printf("Error: Total length mismatch (%d != %d)\n", total_sum, + total_length); exit(-1); - return {}; // 返回空向量,表示生成的数据包总长度不符合要求 + return {}; // 返回空向量,表示生成的数据包总长度不符合要求 } // 返回生成的数据包长度 diff --git a/Core/transmit_protocol/Channel_Simulator/Flow_Channel_Simulator.cpp b/Core/transmit_protocol/Channel_Simulator/Flow_Channel_Simulator.cpp index f718612..22749dc 100644 --- a/Core/transmit_protocol/Channel_Simulator/Flow_Channel_Simulator.cpp +++ b/Core/transmit_protocol/Channel_Simulator/Flow_Channel_Simulator.cpp @@ -1,17 +1,12 @@ #include "Flow_Channel_Simulator.h" - - #ifdef _USE_GTEST #include "Packet_Channel_Simulator.h" #include "global.h" #include using namespace Psc; -class Flow_Channel_Simulator_Test : public ::testing::Test { - -}; - +class Flow_Channel_Simulator_Test : public ::testing::Test {}; // 测试流数据模拟器 可以取光所有数据 TEST_F(Flow_Channel_Simulator_Test, could_recv_all_0) { @@ -32,5 +27,4 @@ TEST_F(Flow_Channel_Simulator_Test, could_recv_all_0) { EXPECT_EQ(fcs.get_buffer_size(&p2), 0); } - #endif \ No newline at end of file diff --git a/Core/transmit_protocol/Channel_Simulator/Packet_Channel_Simulator.cpp b/Core/transmit_protocol/Channel_Simulator/Packet_Channel_Simulator.cpp index 0b54322..f9e9e25 100644 --- a/Core/transmit_protocol/Channel_Simulator/Packet_Channel_Simulator.cpp +++ b/Core/transmit_protocol/Channel_Simulator/Packet_Channel_Simulator.cpp @@ -6,7 +6,6 @@ #include #include - #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #include #elif !defined(__unix) @@ -14,211 +13,217 @@ #endif #ifdef __unix -#include #include -#include #include +#include +#include #endif namespace Psc { /* get system time */ -void timeofday(long *sec, long *usec) -{ +void timeofday(long *sec, long *usec) { #if defined(__unix) - struct timeval time; - gettimeofday(&time, NULL); - if (sec) *sec = time.tv_sec; - if (usec) *usec = time.tv_usec; + struct timeval time; + gettimeofday(&time, NULL); + if (sec) + *sec = time.tv_sec; + if (usec) + *usec = time.tv_usec; #else - static long mode = 0, addsec = 0; - BOOL retval; - static IINT64 freq = 1; - IINT64 qpc; - if (mode == 0) { - retval = QueryPerformanceFrequency((LARGE_INTEGER*)&freq); - freq = (freq == 0)? 1 : freq; - retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc); - addsec = (long)time(NULL); - addsec = addsec - (long)((qpc / freq) & 0x7fffffff); - mode = 1; - } - retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc); - retval = retval * 2; - if (sec) *sec = (long)(qpc / freq) + addsec; - if (usec) *usec = (long)((qpc % freq) * 1000000 / freq); + static long mode = 0, addsec = 0; + BOOL retval; + static IINT64 freq = 1; + IINT64 qpc; + if (mode == 0) { + retval = QueryPerformanceFrequency((LARGE_INTEGER *)&freq); + freq = (freq == 0) ? 1 : freq; + retval = QueryPerformanceCounter((LARGE_INTEGER *)&qpc); + addsec = (long)time(NULL); + addsec = addsec - (long)((qpc / freq) & 0x7fffffff); + mode = 1; + } + retval = QueryPerformanceCounter((LARGE_INTEGER *)&qpc); + retval = retval * 2; + if (sec) + *sec = (long)(qpc / freq) + addsec; + if (usec) + *usec = (long)((qpc % freq) * 1000000 / freq); #endif } /* get clock in millisecond 64 */ -IINT64 clock64(void) -{ - long s, u; - IINT64 value; - itimeofday(&s, &u); - value = ((IINT64)s) * 1000 + (u / 1000); - return value; +IINT64 clock64(void) { + long s, u; + IINT64 value; + itimeofday(&s, &u); + value = ((IINT64)s) * 1000 + (u / 1000); + return value; } -IUINT32 get_clock() -{ - return (IUINT32)(iclock64() & 0xfffffffful); -} +IUINT32 get_clock() { return (IUINT32)(iclock64() & 0xfffffffful); } /* sleep in millisecond */ void isleep(unsigned long millisecond) { #ifdef __unix /* usleep( time * 1000 ); */ - struct timespec ts; - ts.tv_sec = (time_t)(millisecond / 1000); - ts.tv_nsec = (long)((millisecond % 1000) * 1000000); - /*nanosleep(&ts, NULL);*/ - usleep((millisecond << 10) - (millisecond << 4) - (millisecond << 3)); + struct timespec ts; + ts.tv_sec = (time_t)(millisecond / 1000); + ts.tv_nsec = (long)((millisecond % 1000) * 1000000); + /*nanosleep(&ts, NULL);*/ + usleep((millisecond << 10) - (millisecond << 4) - (millisecond << 3)); #elif defined(_WIN32) - Sleep(millisecond); + Sleep(millisecond); #endif } -Packet_Channel_Simulator::~Packet_Channel_Simulator() { - clear(); -} -Packet_Channel_Simulator::Packet_Channel_Simulator(void* peer1, void* peer2, double error_packet_probability, double lose_packet_probability, int lostrate, int rttmin, - int rttmax, int nmax) -: Channel_Simulator(peer1, peer2), -lose_packet_probability(lose_packet_probability) { - current = iclock(); - this->lostrate = lostrate / 2; // 上面数据是往返丢包率,单程除以2 - this->rttmin = rttmin / 2; - this->rttmax = rttmax / 2; - this->nmax = nmax; - if (error_packet_probability > 1.0) { - printf("error_packet_probability = %f \r\n", error_packet_probability); - exit(-1); - } - this->error_packet_probability = error_packet_probability; +Packet_Channel_Simulator::~Packet_Channel_Simulator() { clear(); } +Packet_Channel_Simulator::Packet_Channel_Simulator( + void *peer1, void *peer2, double error_packet_probability, + double lose_packet_probability, int lostrate, int rttmin, int rttmax, + int nmax) + : Channel_Simulator(peer1, peer2), + lose_packet_probability(lose_packet_probability) { + current = iclock(); + this->lostrate = lostrate / 2; // 上面数据是往返丢包率,单程除以2 + this->rttmin = rttmin / 2; + this->rttmax = rttmax / 2; + this->nmax = nmax; + if (error_packet_probability > 1.0) { + printf("error_packet_probability = %f \r\n", error_packet_probability); + exit(-1); + } + this->error_packet_probability = error_packet_probability; } void Packet_Channel_Simulator::clear() { - std::list::iterator it; - for (it = p12.begin(); it != p12.end(); it++) { - delete *it; - } - for (it = p21.begin(); it != p21.end(); it++) { - delete *it; - } - p12.clear(); - p21.clear(); + std::list::iterator it; + for (it = p12.begin(); it != p12.end(); it++) { + delete *it; + } + for (it = p21.begin(); it != p21.end(); it++) { + delete *it; + } + p12.clear(); + p21.clear(); } -void Packet_Channel_Simulator::send(void* peer, Buf_Type buf, Len_Type len) { - PSC_ASSERT(peer == peer1 || peer == peer2, ""); - if (get_lose_packet_probability()) { - return; - } - if (peer == peer1) { - if (get_random_rtt() < lostrate) return; - if ((int)p12.size() >= nmax) { +void Packet_Channel_Simulator::send(void *peer, Buf_Type buf, Len_Type len) { + PSC_ASSERT(peer == peer1 || peer == peer2, ""); + if (get_lose_packet_probability()) { + return; + } + if (peer == peer1) { + if (get_random_rtt() < lostrate) + return; + if ((int)p12.size() >= nmax) { - std::cout << fmt::format("网卡包太多警告 {}\r\n", p12.size()); - // return; - } - } else { - if (get_random_rtt() < lostrate) return; - if ((int)p21.size() >= nmax) { - std::cout << fmt::format("网卡包太多警告 {}\r\n", p21.size()); - // return; - } + std::cout << fmt::format("网卡包太多警告 {}\r\n", p12.size()); + // return; } - auto pkt = new Packet(buf, len); - current = iclock(); - IUINT32 delay = rttmin; - if (rttmax > rttmin) delay += rand() % (rttmax - rttmin); - pkt->_ts = current + delay; - if (peer == peer1) { - p12.push_back(pkt); - } else { - p21.push_back(pkt); + } else { + if (get_random_rtt() < lostrate) + return; + if ((int)p21.size() >= nmax) { + std::cout << fmt::format("网卡包太多警告 {}\r\n", p21.size()); + // return; } + } + auto pkt = new Packet(buf, len); + current = iclock(); + IUINT32 delay = rttmin; + if (rttmax > rttmin) + delay += rand() % (rttmax - rttmin); + pkt->_ts = current + delay; + if (peer == peer1) { + p12.push_back(pkt); + } else { + p21.push_back(pkt); + } } -int Packet_Channel_Simulator::recv(void* peer, Buf_Type buf, Len_Type len) { - PSC_ASSERT(peer == peer1 || peer == peer2, ""); - std::list::iterator it; - if (peer == peer1) { - it = p21.begin(); - if (p21.size() == 0) return -1; - } else { - it = p12.begin(); - if (p12.size() == 0) return -1; - } - Packet* pkt = *it; - current = iclock(); - if (current < pkt->_ts) { - // printf("current %d 时间小于ts: %d \n",current,pkt->_ts); - return -2; - } - if (len < pkt->_size) { - printf("单包太大 %d, maxsize: %d 不够用! \n", pkt->_size, len); - return -3; - } - if (peer == peer1) { - p21.erase(it); - } else { - p12.erase(it); - } - len = pkt->_size; - IUINT16 crc = xcrc16(pkt->_ptr, pkt->_size); - // 在recv 时候修改数据 - if (get_error_packet_probability()) { - corrupt_data(pkt->_ptr, len, 0.3); - } - IUINT16 crc2 = xcrc16(pkt->_ptr, pkt->_size); - if (crc != crc2) { - this->ps.update(true); - } else { - this->ps.update(false); - } - if (limit.test()) { - printf("模拟器丢包率: %d ‰ %d ‰ \r\n", this->ps.instant, this->ps.average); - } - memcpy(buf, pkt->_ptr, len); - delete pkt; - return len; +int Packet_Channel_Simulator::recv(void *peer, Buf_Type buf, Len_Type len) { + PSC_ASSERT(peer == peer1 || peer == peer2, ""); + std::list::iterator it; + if (peer == peer1) { + it = p21.begin(); + if (p21.size() == 0) + return -1; + } else { + it = p12.begin(); + if (p12.size() == 0) + return -1; + } + Packet *pkt = *it; + current = iclock(); + if (current < pkt->_ts) { + // printf("current %d 时间小于ts: %d \n",current,pkt->_ts); + return -2; + } + if (len < pkt->_size) { + printf("单包太大 %d, maxsize: %d 不够用! \n", pkt->_size, len); + return -3; + } + if (peer == peer1) { + p21.erase(it); + } else { + p12.erase(it); + } + len = pkt->_size; + IUINT16 crc = xcrc16(pkt->_ptr, pkt->_size); + // 在recv 时候修改数据 + if (get_error_packet_probability()) { + corrupt_data(pkt->_ptr, len, 0.3); + } + IUINT16 crc2 = xcrc16(pkt->_ptr, pkt->_size); + if (crc != crc2) { + this->ps.update(true); + } else { + this->ps.update(false); + } + if (limit.test()) { + printf("模拟器丢包率: %d ‰ %d ‰ \r\n", this->ps.instant, this->ps.average); + } + memcpy(buf, pkt->_ptr, len); + delete pkt; + return len; } int Packet_Channel_Simulator::get_random_rtt() { - std::normal_distribution<> dist((rttmin + rttmax) / 2, 10.0); - double val = dist(gen); - if (val < 0) val = 0; // RTT 不可能为负 - return static_cast(val); + std::normal_distribution<> dist((rttmin + rttmax) / 2, 10.0); + double val = dist(gen); + if (val < 0) + val = 0; // RTT 不可能为负 + return static_cast(val); } -bool Packet_Channel_Simulator::get_error_packet_probability() { - std::bernoulli_distribution dist(error_packet_probability); - return dist(gen); +bool Packet_Channel_Simulator::get_error_packet_probability() { + std::bernoulli_distribution dist(error_packet_probability); + return dist(gen); } bool Packet_Channel_Simulator::get_lose_packet_probability() { - std::bernoulli_distribution dist(lose_packet_probability); - return dist(gen); + std::bernoulli_distribution dist(lose_packet_probability); + return dist(gen); } Len_Type generate_random_size(Len_Type min_size, Len_Type max_size) { - // 初始化随机数生成器 - std::random_device rd; - std::mt19937 gen(rd()); // Mersenne Twister 引擎 - std::uniform_int_distribution<> dist(min_size, max_size); // 随机生成整数,范围[min_size, max_size] + // 初始化随机数生成器 + std::random_device rd; + std::mt19937 gen(rd()); // Mersenne Twister 引擎 + std::uniform_int_distribution<> dist( + min_size, max_size); // 随机生成整数,范围[min_size, max_size] - return dist(gen); // 返回一个随机的大小 + return dist(gen); // 返回一个随机的大小 } std::string generate_random_string(Len_Type length) { - const std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - std::string result; - for (int i = 0; i < length; ++i) { - result += chars[rand() % chars.size()]; - } - return result; + const std::string chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::string result; + for (int i = 0; i < length; ++i) { + result += chars[rand() % chars.size()]; + } + return result; } - std::string generate_cyclic_string(int length) { - std::string result; - for (int i = 0; i < length; ++i) { - result += std::to_string(i % 10); // 使用 `i % 10` 循环0到9 - } - return result; + std::string result; + for (int i = 0; i < length; ++i) { + result += std::to_string(i % 10); // 使用 `i % 10` 循环0到9 + } + return result; } } \ No newline at end of file diff --git a/Core/transmit_protocol/core/main.h b/Core/transmit_protocol/core/main.h index ded88bd..9bcfec0 100644 --- a/Core/transmit_protocol/core/main.h +++ b/Core/transmit_protocol/core/main.h @@ -4,62 +4,61 @@ #include #else - #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - #include - #else - typedef char bool; - #define true 1 - #define false 0 - #endif +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#else +typedef char bool; +#define true 1 +#define false 0 +#endif #endif - //===================================================================== // 32BIT INTEGER DEFINITION //===================================================================== #ifndef __INTEGER_32_BITS__ #define __INTEGER_32_BITS__ -#if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ - defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ - defined(_M_AMD64) - typedef unsigned int ISTDUINT32; - typedef int ISTDINT32; +#if defined(_WIN64) || defined(WIN64) || defined(__amd64__) || \ + defined(__x86_64) || defined(__x86_64__) || defined(_M_IA64) || \ + defined(_M_AMD64) +typedef unsigned int ISTDUINT32; +typedef int ISTDINT32; - // ---------------- Keil ARMCC / ARMClang ---------------- -#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__ARMCOMPILER_VERSION) - #include - typedef uint32_t ISTDUINT32; - typedef int32_t ISTDINT32; +// ---------------- Keil ARMCC / ARMClang ---------------- +#elif defined(__CC_ARM) || defined(__ARMCC_VERSION) || \ + defined(__ARMCOMPILER_VERSION) +#include +typedef uint32_t ISTDUINT32; +typedef int32_t ISTDINT32; -#elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ - defined(__i386) || defined(_M_X86) - typedef unsigned long ISTDUINT32; - typedef long ISTDINT32; +#elif defined(_WIN32) || defined(WIN32) || defined(__i386__) || \ + defined(__i386) || defined(_M_X86) +typedef unsigned long ISTDUINT32; +typedef long ISTDINT32; #elif defined(__MACOS__) - typedef UInt32 ISTDUINT32; - typedef SInt32 ISTDINT32; +typedef UInt32 ISTDUINT32; +typedef SInt32 ISTDINT32; #elif defined(__APPLE__) && defined(__MACH__) - #include - typedef u_int32_t ISTDUINT32; - typedef int32_t ISTDINT32; +#include +typedef u_int32_t ISTDUINT32; +typedef int32_t ISTDINT32; #elif defined(__BEOS__) - #include - typedef u_int32_t ISTDUINT32; - typedef int32_t ISTDINT32; +#include +typedef u_int32_t ISTDUINT32; +typedef int32_t ISTDINT32; #elif (defined(_MSC_VER) || defined(__BORLANDC__)) && (!defined(__MSDOS__)) - typedef unsigned __int32 ISTDUINT32; - typedef __int32 ISTDINT32; +typedef unsigned __int32 ISTDUINT32; +typedef __int32 ISTDINT32; #elif defined(__GNUC__) - #include - typedef uint32_t ISTDUINT32; - typedef int32_t ISTDINT32; +#include +typedef uint32_t ISTDUINT32; +typedef int32_t ISTDINT32; #else - typedef unsigned long ISTDUINT32; - typedef long ISTDINT32; +typedef unsigned long ISTDUINT32; +typedef long ISTDINT32; #endif #endif - //===================================================================== // Integer Definition //===================================================================== @@ -102,10 +101,10 @@ typedef long long IINT64; #endif #endif - #ifndef __IUINT64_DEFINED #define __IUINT64_DEFINED -#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || defined(__ARMCOMPILER_VERSION) +#if defined(__CC_ARM) || defined(__ARMCC_VERSION) || \ + defined(__ARMCOMPILER_VERSION) typedef unsigned long long IUINT64; #elif defined(_MSC_VER) || defined(__BORLANDC__) typedef unsigned __int64 IUINT64; @@ -118,9 +117,9 @@ typedef unsigned long long IUINT64; #if defined(__GNUC__) #if (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) -#define INLINE __inline__ __attribute__((always_inline)) +#define INLINE __inline__ __attribute__((always_inline)) #else -#define INLINE __inline__ +#define INLINE __inline__ #endif #elif (defined(_MSC_VER) || defined(__BORLANDC__) || defined(__WATCOMC__)) @@ -134,23 +133,20 @@ typedef unsigned long long IUINT64; #define inline INLINE #endif - - -typedef void* (*Malloc_Func)(size_t); -typedef void (*Free_Func)(void*); - +typedef void *(*Malloc_Func)(size_t); +typedef void (*Free_Func)(void *); #ifdef __cplusplus extern "C" { #endif - void* g_malloc(size_t size); - void g_free(void *ptr); - void set_allocator(Malloc_Func malloc_func, Free_Func free_func); +void *g_malloc(size_t size); +void g_free(void *ptr); +void set_allocator(Malloc_Func malloc_func, Free_Func free_func); #ifdef __cplusplus } #endif -typedef char* Buf_Type; +typedef char *Buf_Type; typedef IUINT16 Len_Type; typedef char Error_Code; typedef struct ND ND; @@ -159,98 +155,78 @@ typedef struct Ptr_Node Ptr_Node; typedef struct Ptr_List Ptr_List; typedef IUINT16 Packet_Seq_Type; - struct ND { - ND* next; - Buf_Type buf; - Len_Type len; + ND *next; + Buf_Type buf; + Len_Type len; }; - struct DL { - ND* head; - ND* tail; - void *s; - void (*lock_func)(void*); - void (*unlock_func)(void*); + ND *head; + ND *tail; + void *s; + void (*lock_func)(void *); + void (*unlock_func)(void *); }; - - -DL* init_mem_list(); -void free_mem_list(DL* dl); -void push_mem(DL* list, Buf_Type d, Len_Type size); -ND* get_clear_mem_list_data(DL* list); -void clear_all_node(DL* dl); -ND* get_all_mem_expect_header_len(DL* dl, Len_Type header_len); -ND* get_all_mem(DL* dl); -Len_Type get_mem_node_num(DL* dl); -void free_mem_head(ND* head); - +DL *init_mem_list(); +void free_mem_list(DL *dl); +void push_mem(DL *list, Buf_Type d, Len_Type size); +ND *get_clear_mem_list_data(DL *list); +void clear_all_node(DL *dl); +ND *get_all_mem_expect_header_len(DL *dl, Len_Type header_len); +ND *get_all_mem(DL *dl); +Len_Type get_mem_node_num(DL *dl); +void free_mem_head(ND *head); // 开关中断 互斥条件 // void lock(Serial_FD serial); // void unlock(Serial_FD serial); - - - - - // 双向链表 struct Ptr_Node { - Ptr_Node* next; - Ptr_Node* prev; - void* ptr; + Ptr_Node *next; + Ptr_Node *prev; + void *ptr; }; - struct Ptr_List { - Ptr_Node* head; - Ptr_Node* tail; - Len_Type len; - void (*free_ptr_func)(void*); // 如果为空代表存的是引用 + Ptr_Node *head; + Ptr_Node *tail; + Len_Type len; + void (*free_ptr_func)(void *); // 如果为空代表存的是引用 }; +Ptr_List *Ptr_List_new(void (*free_ptr_func)(void *)); +void Ptr_List_delete(Ptr_List *list); +void Ptr_List_append(Ptr_List *list, void *ptr); +void Ptr_List_prepend(Ptr_List *list, void *ptr); +void Ptr_List_insert_before_ptr(Ptr_List *list, Ptr_Node *pos, void *ptr); +void Ptr_List_insert_after_ptr(Ptr_List *list, Ptr_Node *pos, void *ptr); +void Ptr_List_remove_ptr(Ptr_List *list, Ptr_Node *pos); +void *Ptr_List_pop_ptr(Ptr_List *list, Ptr_Node *pos); +Ptr_Node *Ptr_List_pop_all(Ptr_List *list); +void Ptr_List_delete_tail_from(Ptr_List *list, Ptr_Node *pos); +void Ptr_List_delete_all(Ptr_List *dl); -Ptr_List* Ptr_List_new(void (*free_ptr_func)(void*)); -void Ptr_List_delete(Ptr_List* list); -void Ptr_List_append(Ptr_List* list, void* ptr); -void Ptr_List_prepend(Ptr_List* list, void* ptr); -void Ptr_List_insert_before_ptr(Ptr_List* list, Ptr_Node* pos, void* ptr); -void Ptr_List_insert_after_ptr(Ptr_List* list, Ptr_Node* pos, void* ptr); -void Ptr_List_remove_ptr(Ptr_List* list, Ptr_Node* pos); -void* Ptr_List_pop_ptr(Ptr_List* list, Ptr_Node* pos); -Ptr_Node* Ptr_List_pop_all(Ptr_List* list); -void Ptr_List_delete_tail_from(Ptr_List* list, Ptr_Node* pos); -void Ptr_List_delete_all(Ptr_List* dl); - - - - - - - - - - -typedef void (*Handle_Piece)(char* data, void* user); +typedef void (*Handle_Piece)(char *data, void *user); typedef struct Piece_Manager Piece_Manager; struct Piece_Manager { - Handle_Piece handle_piece; - Buf_Type buf; - Len_Type cur_size; - Len_Type piece_size; + Handle_Piece handle_piece; + Buf_Type buf; + Len_Type cur_size; + Len_Type piece_size; }; -Piece_Manager* create_piece_manager(Len_Type piece_size, Handle_Piece handle_piece); -void release_piece_manager(Piece_Manager* piece_manager); -void piece_manager_push_data(Piece_Manager* piece_manager, Buf_Type buf, Len_Type len, void* user); +Piece_Manager *create_piece_manager(Len_Type piece_size, + Handle_Piece handle_piece); +void release_piece_manager(Piece_Manager *piece_manager); +void piece_manager_push_data(Piece_Manager *piece_manager, Buf_Type buf, + Len_Type len, void *user); // 如果 _itimediff(a, b) > 0,说明 a 在 b 之后。 // 如果 _itimediff(a, b) < 0,说明 a 在 b 之前。 // 如果等于 0,则相等 -static inline long _itimediff(IUINT32 later, IUINT32 earlier) -{ - return ((IINT32)(later - earlier)); +static inline long _itimediff(IUINT32 later, IUINT32 earlier) { + return ((IINT32)(later - earlier)); } \ No newline at end of file diff --git a/Core/transmit_protocol/core/statistics.cpp b/Core/transmit_protocol/core/statistics.cpp index c9e9d9f..a19ba7b 100644 --- a/Core/transmit_protocol/core/statistics.cpp +++ b/Core/transmit_protocol/core/statistics.cpp @@ -1,8 +1,8 @@ #include "statistics.h" #include #ifndef __cplusplus - #define max(a,b) (((a) > (b)) ? (a) : (b)) - #define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) #endif // // void Value_Statistics_init(Value_Statistics* v) { @@ -18,7 +18,8 @@ // float average_times = 10.0f; // 平均取近十次 // v->instant = value; // if (v->average != -1) { -// v->average = v->average * (average_times - 1.0f) / average_times + v->instant * (1.0f) / average_times; +// v->average = v->average * (average_times - 1.0f) / average_times + +// v->instant * (1.0f) / average_times; // } else { // v->average = v->instant; // } @@ -33,7 +34,8 @@ // v->total_max = 10; // } // // -100 代表失败了 100次加入统计 100 代表成功了 100次加入统计 -// void Probability_Statistics_update(Probability_Statistics* v, IINT32 count_change) { +// void Probability_Statistics_update(Probability_Statistics* v, IINT32 +// count_change) { // if (count_change == false) { // count_change = -1; // } @@ -82,7 +84,8 @@ // // v->instant_speed = v->total / (float)true_period; // // float average_times = 10.0f; // 平均速度取近十次 // // if (v->average_speed != -1) { -// // v->average_speed = v->average_speed * (average_times - 1.0f)/average_times + v->instant_speed * (1.0f)/average_times; +// // v->average_speed = v->average_speed * (average_times +// - 1.0f)/average_times + v->instant_speed * (1.0f)/average_times; // // } else { // // v->average_speed = v->instant_speed; // // } @@ -102,7 +105,8 @@ // // 平均速度 // float average_times = 10.0f; // if (v->average_speed >= 0) { -// v->average_speed = v->average_speed * (average_times - 1.0f)/average_times +// v->average_speed = v->average_speed * (average_times +// - 1.0f)/average_times // + v->instant_speed * (1.0f)/average_times; // } else { // v->average_speed = v->instant_speed; diff --git a/Core/transmit_protocol/core/statistics.h b/Core/transmit_protocol/core/statistics.h index 36f4d94..d96b442 100644 --- a/Core/transmit_protocol/core/statistics.h +++ b/Core/transmit_protocol/core/statistics.h @@ -5,7 +5,6 @@ extern "C" { #endif #include "main.h" - // typedef struct Speed_Statistics Speed_Statistics; // typedef struct Value_Statistics Value_Statistics; // typedef struct Probability_Statistics Probability_Statistics; @@ -41,10 +40,10 @@ extern "C" { // IUINT32 total_max; // 总次数 // }; // void Probability_Statistics_init(Probability_Statistics* v); -// void Probability_Statistics_update(Probability_Statistics* v, IINT32 count_change); +// void Probability_Statistics_update(Probability_Statistics* v, IINT32 +// count_change); // - #ifdef __cplusplus } #endif diff --git a/Core/transmit_protocol/dtls/handshake.h b/Core/transmit_protocol/dtls/handshake.h index ebea451..fb8a4d5 100644 --- a/Core/transmit_protocol/dtls/handshake.h +++ b/Core/transmit_protocol/dtls/handshake.h @@ -1,7 +1,3 @@ #pragma once - - -class handshake { - -}; \ No newline at end of file +class handshake {}; \ No newline at end of file diff --git a/Core/transmit_protocol/export.cpp b/Core/transmit_protocol/export.cpp index 8a722ba..147b8be 100644 --- a/Core/transmit_protocol/export.cpp +++ b/Core/transmit_protocol/export.cpp @@ -8,141 +8,103 @@ // https://github.com/skywind3000/kcp/wiki/KCP-Best-Practice // https://github.com/skywind3000/kcp/wiki/Network-Layer - - - - - // 循环冗余校验相关 -static const unsigned int crc32_table[] = -{ - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, - 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, - 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, - 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, - 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, - 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, - 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, - 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, - 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, - 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, - 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, - 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, - 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, - 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, - 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, - 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, - 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, - 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, - 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, - 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, - 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, - 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, - 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, - 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, - 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, - 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, - 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, - 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, - 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, - 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, - 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, - 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, - 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, - 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, - 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, - 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, - 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, - 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, - 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, - 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, - 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, - 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, - 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 -}; +static const unsigned int crc32_table[] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; -IUINT32 xcrc32(void* buf, IUINT32 len) { - unsigned char* p = (unsigned char*)buf; - IUINT32 crc = 0; - while (len--) { - crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *p) & 255]; - p++; - } - return crc; +IUINT32 xcrc32(void *buf, IUINT32 len) { + unsigned char *p = (unsigned char *)buf; + IUINT32 crc = 0; + while (len--) { + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *p) & 255]; + p++; + } + return crc; } +const IUINT16 crc_ta_8[256] = + {/* CRC 字节余式表 */ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, + 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, + 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, + 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, + 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, + 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, + 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, + 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, + 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, + 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, + 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, + 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, + 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, + 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, + 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, + 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, + 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, + 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, + 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, + 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, + 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, + 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, + 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, + 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, + 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, + 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0}; +IUINT16 xcrc16(void *buf, IUINT16 len) { + IUINT16 crc = 0xffff; + unsigned char *ptr = (unsigned char *)buf; + while (len-- != 0) { + IUINT16 high = (unsigned int)(crc / 256); // 取CRC高8位 + crc <<= 8; + crc ^= crc_ta_8[high ^ *ptr]; + ptr++; + } - - -const IUINT16 crc_ta_8[256]={ /* CRC 字节余式表 */ - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, - 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, - 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, - 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, - 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, - 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, - 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, - 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, - 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, - 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, - 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, - 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, - 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, - 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, - 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, - 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, - 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, - 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, - 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, - 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, - 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, - 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, - 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 -}; - - -IUINT16 xcrc16(void *buf, IUINT16 len) -{ - IUINT16 crc = 0xffff; - unsigned char* ptr = (unsigned char*)buf; - while(len-- != 0) - { - IUINT16 high = (unsigned int)(crc/256); //取CRC高8位 - crc <<= 8; - crc ^= crc_ta_8[high^*ptr]; - ptr++; - } - - return crc; + return crc; } diff --git a/Core/transmit_protocol/feclib/documentation.html b/Core/transmit_protocol/feclib/documentation.html index 30e6394..5472d3a 100644 --- a/Core/transmit_protocol/feclib/documentation.html +++ b/Core/transmit_protocol/feclib/documentation.html @@ -5,63 +5,63 @@ locate errors that occured during transmission, but it will regenerate any packets the have been lost along the way.

It consists of an encoder and a decoder. The encoder is fed a stream of data -which it breaks up into packets. These packets can then be sent over an -unreliable transport mechanism, typically UDP. The decoder can then -reconstruct lost packets from redundant packets sent by the encoder. + which it breaks up into packets. These packets can then be sent over an + unreliable transport mechanism, typically UDP. The decoder can then + reconstruct lost packets from redundant packets sent by the encoder.

Like other implementations, the encoder groups n packets of payload -together and then adds k redundant packets to it. The receiver can only start -to reconstruct any of the lost payload once it has received at least n packets -in total. + together and then adds k redundant packets to it. The receiver can only start + to reconstruct any of the lost payload once it has received at least n packets + in total.

I wanted everything to be as clean as possible, with no fancy features. -Since it's open source, anyone is g_free to improve things as they see fit. -Contributions should start with the to do list at the end of this document. + Since it's open source, anyone is g_free to improve things as they see fit. + Contributions should start with the to do list at the end of this document.

My intention was that it can be used in those cases where there is no back -channel e.g. one-way satellite link. So, if the library has been properly -configured, all data will be recovered, -even if many megabytes is lost due to external events like thunder storms. + channel e.g. one-way satellite link. So, if the library has been properly + configured, all data will be recovered, + even if many megabytes is lost due to external events like thunder storms.

Parameters

This implementation uses band matrices (instead of Van Der Monde matrices) for improved performance. It is extremely versatile, because it allows you to set the following parameters :
    -
  1. s the size of each packet, excluding headers. (See 5 below). -
  2. n the number of packets that are grouped together. This determines - latency i.e. the receiver may end up having to wait until the whole group - was received before it has enough data to output the first packet. - Unless you have latency or memory concerns, you may as - well set n to the number of packets you are sending. - (See 3 below) -
  3. k the number of redundant packets sent for each group. - k / (n + k) should preferrably be much higher than the the error rate of - the transport mechanism on a per packet basis. Note that the k redundant - packets are accessed very frequently, so it is advisible that k * s should - be less than the amount of physical memory (RAM). Also note that as n gets - smaller the chance to loose k of them increases (especially if there are - burst losses), so n should be as large as possible. Usually the k * s - will equal to the maximum expected amount of data that could be lost. -

    Maybe someone will write a function that uses probability models to - work out the smallest suitable value of k... -

  4. w the width of the band in the band matrix. The larger w, the - more processing power is needed. Typically 40 is a good default. In the - unfortunate case that you loose a packet and all 40 redundant packets in - its column, the reconstruction will fail. Fortunely - these 41 packets are pseudo randomly distributed amoung the k + n packets - so the chance of that happening is not great. -
  5. g The size of the Galois field is 2g. The - computing time increases linearly with g - (unlike other O(1) implementations). - Because a field has only 1 element which does not have - a multiplication inverse, the probability of not being able to find a - spil element when we have k - i rows left to choose from is - 2-g * (k - i). So a good value of g is 2, 3 or 4. - s must be a multiple of g * 4. -
  6. b the number of bits per second that the encoder should limit the - output to. This prevents network overload. Setting this to 0, implies that - it should send as fast as possible. +
  7. s the size of each packet, excluding headers. (See 5 below). +
  8. n the number of packets that are grouped together. This determines + latency i.e. the receiver may end up having to wait until the whole group + was received before it has enough data to output the first packet. + Unless you have latency or memory concerns, you may as + well set n to the number of packets you are sending. + (See 3 below) +
  9. k the number of redundant packets sent for each group. + k / (n + k) should preferrably be much higher than the the error rate of + the transport mechanism on a per packet basis. Note that the k redundant + packets are accessed very frequently, so it is advisible that k * s should + be less than the amount of physical memory (RAM). Also note that as n gets + smaller the chance to loose k of them increases (especially if there are + burst losses), so n should be as large as possible. Usually the k * s + will equal to the maximum expected amount of data that could be lost. +

    Maybe someone will write a function that uses probability models to + work out the smallest suitable value of k... +

  10. w the width of the band in the band matrix. The larger w, the + more processing power is needed. Typically 40 is a good default. In the + unfortunate case that you loose a packet and all 40 redundant packets in + its column, the reconstruction will fail. Fortunely + these 41 packets are pseudo randomly distributed amoung the k + n packets + so the chance of that happening is not great. +
  11. g The size of the Galois field is 2g. The + computing time increases linearly with g + (unlike other O(1) implementations). + Because a field has only 1 element which does not have + a multiplication inverse, the probability of not being able to find a + spil element when we have k - i rows left to choose from is + 2-g * (k - i). So a good value of g is 2, 3 or 4. + s must be a multiple of g * 4. +
  12. b the number of bits per second that the encoder should limit the + output to. This prevents network overload. Setting this to 0, implies that + it should send as fast as possible.

Functions

@@ -102,26 +102,26 @@ void DeleteFecDecoder (fecDecoder *f);

To Do list

    -
  1. Implement sub channels Currently we send a very large header -packet. Because we need it at the receiver, it must be sent with every -packets. -

    It consumes less bandwidth to implement a sub channel to send the 20 odd -bytes of control information : -Now the header is e.g. 2 bytes. The first bytes sends would be a simple -modulo 28 counter. The second byte would contain 1 byte of -control data if the first byte is less than 20, and would be a checksum byte -otherwise. This checksum scheme can also use Galois Fields and Gaussian -elimination, but it's parameters must chosen so that it will still function -under the worst possible error rates. -

  2. Optimizations -
  3. Packet checksum Let the library send its own checksums incase the -UDP checksum still lets some bad packets get through. -
  4. Non field rings It is quite possible that there exists some -polynomials that are not primative, and the resultant ring is not a field, but -most of the ring is invertible, and they can be manipulated for even faster -operation. This needs to be investigated. -
  5. Overflow of i If more than 2 billion packets are send, problem may -occur. We need to fi this. +
  6. Implement sub channels Currently we send a very large header + packet. Because we need it at the receiver, it must be sent with every + packets. +

    It consumes less bandwidth to implement a sub channel to send the 20 odd + bytes of control information : + Now the header is e.g. 2 bytes. The first bytes sends would be a simple + modulo 28 counter. The second byte would contain 1 byte of + control data if the first byte is less than 20, and would be a checksum byte + otherwise. This checksum scheme can also use Galois Fields and Gaussian + elimination, but it's parameters must chosen so that it will still function + under the worst possible error rates. +

  7. Optimizations +
  8. Packet checksum Let the library send its own checksums incase the + UDP checksum still lets some bad packets get through. +
  9. Non field rings It is quite possible that there exists some + polynomials that are not primative, and the resultant ring is not a field, but + most of the ring is invertible, and they can be manipulated for even faster + operation. This needs to be investigated. +
  10. Overflow of i If more than 2 billion packets are send, problem may + occur. We need to fi this.

Copyright

diff --git a/Core/transmit_protocol/feclib/fec.c b/Core/transmit_protocol/feclib/fec.c index c33d8f7..9c1b688 100644 --- a/Core/transmit_protocol/feclib/fec.c +++ b/Core/transmit_protocol/feclib/fec.c @@ -4,62 +4,65 @@ #include #ifndef max -#define max(x,y) ((x) > (y) ? (x) : (y)) +#define max(x, y) ((x) > (y) ? (x) : (y)) #endif #ifndef min -#define min(x,y) ((x) < (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) #endif +static unsigned + poly[] = {0x1, 0x2, 0x7, 0xb, 0x13, 0x25, + 0x43, 0x83, 0x11b, 0x203, 0x409, 0x805, + 0x1009, 0x201b, 0x4021, 0x8003, 0x1002b}; // See the second part + // of fectest.c +#pragma warning(disable : 4018) -static unsigned poly[]={ - 0x1, 0x2, 0x7, 0xb, 0x13, 0x25, 0x43, 0x83, 0x11b, 0x203, 0x409, 0x805, - 0x1009, 0x201b, 0x4021, 0x8003, 0x1002b -}; // See the second part of fectest.c - -#pragma warning(disable:4018) - -static void MAC (__int32_t multiplier, fecPayload *source, fecPayload *dest, __int32_t g, - __int32_t s) -{ // Multiply with scalar and then accumulate. +static void MAC(__int32_t multiplier, fecPayload *source, fecPayload *dest, + __int32_t g, + __int32_t s) { // Multiply with scalar and then accumulate. __int32_t i, j, k, l; - for (j = 0; j < s / sizeof (*source); j += s / g / sizeof (*source)) { - for (k = multiplier, l = 0; k; k >>= 1, l += s / g / sizeof (*source)) { + for (j = 0; j < s / sizeof(*source); j += s / g / sizeof(*source)) { + for (k = multiplier, l = 0; k; k >>= 1, l += s / g / sizeof(*source)) { if (k & 1) { - for (i = 0; i < s / g / sizeof (*source); i++) { + for (i = 0; i < s / g / sizeof(*source); i++) { dest[l + i] ^= source[j + i]; } } } multiplier <<= 1; - if (multiplier >= (1<= (1 << g)) + multiplier ^= poly[g]; } } -fec_encoder *new_fec_encoder (void *userData, - User_Send userSend, - char **errorMessage, - __int32_t s, __int32_t n, __int32_t k, __int32_t w, __int32_t g, __int32_t b) -{ +fec_encoder *new_fec_encoder(void *userData, User_Send userSend, + char **errorMessage, __int32_t s, __int32_t n, + __int32_t k, __int32_t w, __int32_t g, + __int32_t b) { fec_encoder *f; Fec_Header *h; - if (s % (g * sizeof (__int32_t)) != 0 || g > 16 || (g >> GBITS)) { - if (errorMessage) *errorMessage = "FEC : Illegal Galois field size "; + if (s % (g * sizeof(__int32_t)) != 0 || g > 16 || (g >> GBITS)) { + if (errorMessage) + *errorMessage = "FEC : Illegal Galois field size "; return NULL; } if (k >> KBITS) { - if (errorMessage) *errorMessage = "FEC : k is too large"; + if (errorMessage) + *errorMessage = "FEC : k is too large"; return NULL; } if (w >> WBITS) { - if (errorMessage) *errorMessage = "FEC : w is too large"; + if (errorMessage) + *errorMessage = "FEC : w is too large"; return NULL; } - f = (fec_encoder *) malloc (sizeof (*f) + sizeof (*h) + s * (k + 1)); + f = (fec_encoder *)malloc(sizeof(*f) + sizeof(*h) + s * (k + 1)); if (!f) { - if (errorMessage) *errorMessage = "FEC : Out of memory"; - g_free (f); + if (errorMessage) + *errorMessage = "FEC : Out of memory"; + g_free(f); return NULL; } f->userData = userData; @@ -72,67 +75,71 @@ fec_encoder *new_fec_encoder (void *userData, f->e.n = n; f->e.i = 0; f->lastTime = 0; - h = (Fec_Header*) (s * k + (char*) (f + 1)); - h->n = (n); - h->kwg = (k | (w << KBITS) | (g << (KBITS + WBITS))); - memset (f + 1, 0, s * k); // Initialize the redundant packets. - if (errorMessage) *errorMessage = NULL; + h = (Fec_Header *)(s * k + (char *)(f + 1)); + h->n = (n); + h->kwg = (k | (w << KBITS) | (g << (KBITS + WBITS))); + memset(f + 1, 0, s * k); // Initialize the redundant packets. + if (errorMessage) + *errorMessage = NULL; return f; } -static void AddToRedundant (fecPayload *buf, fec_enc_dec *e, __int32_t i) -{ // This is called by both the encoder and the decoder when they process the -// payload. But this code is also repeated where the decoder sets up the -// matrix. -// I suppose a lot of pseudo random stuff can be tried, but in the end nature -// will add its own randomness by way of the packets it destroys. +static void +AddToRedundant(fecPayload *buf, fec_enc_dec *e, + __int32_t i) { // This is called by both the encoder and the + // decoder when they process the + // payload. But this code is also repeated where the decoder sets up the + // matrix. + // I suppose a lot of pseudo random stuff can be tried, but in the end nature + // will add its own randomness by way of the packets it destroys. __int32_t row, mid = i * e->w % e->k; // e.g. mid = i * 87654321 % e->k __uint32_t coef = i + 1; - for (row = max (0, min (mid, e->k - e->w) - e->w); - row < min (e->k, max (mid, e->w) + e->w); row++) { + for (row = max(0, min(mid, e->k - e->w) - e->w); + row < min(e->k, max(mid, e->w) + e->w); row++) { coef *= 1763689789; - MAC (coef >> (32 - e->g), - buf, (fecPayload*) (row * e->s + (char *)(e + 1)), e->g, e->s); + MAC(coef >> (32 - e->g), buf, (fecPayload *)(row * e->s + (char *)(e + 1)), + e->g, e->s); } -// What actually needs to be investigated is the problems at the edges : -// With "for (row = max (mid - e->w, 0); row < min (mid + e->w, e->k); row++)" -// there are columns with less than 2w non-zero entries which is a weakness. -// Apart for the current solution, -// another solution would be to have row "-1" wrap around into row k - 1 and -// row "k" into row 0 etc. The matrix will not be a band matrix which -// complicates things. + // What actually needs to be investigated is the problems at the edges : + // With "for (row = max (mid - e->w, 0); row < min (mid + e->w, e->k); row++)" + // there are columns with less than 2w non-zero entries which is a weakness. + // Apart for the current solution, + // another solution would be to have row "-1" wrap around into row k - 1 and + // row "k" into row 0 etc. The matrix will not be a band matrix which + // complicates things. } - -static void SendWithDelay (fecPayload *buf, fec_encoder *f) -{ - Fec_Header *h = (Fec_Header*)(f->e.k * f->e.s + (char*)(f + 1)); +static void SendWithDelay(fecPayload *buf, fec_encoder *f) { + Fec_Header *h = (Fec_Header *)(f->e.k * f->e.s + (char *)(f + 1)); __int32_t tick; - __int32_t s = f->e.s + sizeof (*h); + __int32_t s = f->e.s + sizeof(*h); - memcpy (h + 1, buf, f->e.s); + memcpy(h + 1, buf, f->e.s); -// if (f->b > 0) { -// tick = GetTickCount (); -// if (f->lastTime == 0) f->lastTime = tick; -// else { -// if (tick - f->lastTime < s * 8000 / f->b) -// #if !defined(WIN32) && !defined(__CYGWIN__) -// usleep ((s * 8000 / f->b - tick + f->lastTime) * 1000); -// #else -// Sleep (s * 8000 / f->b - tick + f->lastTime); -// #endif -// f->lastTime += s * 8000 / f->b; -// if (tick - f->lastTime > 100) f->lastTime += (tick-f->lastTime-100) / 2; -// } // If we are more than a 10th of a second behind we reduce the bitrate. -// } + // if (f->b > 0) { + // tick = GetTickCount (); + // if (f->lastTime == 0) f->lastTime = tick; + // else { + // if (tick - f->lastTime < s * 8000 / f->b) + // #if !defined(WIN32) && !defined(__CYGWIN__) + // usleep ((s * 8000 / f->b - tick + f->lastTime) * 1000); + // #else + // Sleep (s * 8000 / f->b - tick + f->lastTime); + // #endif + // f->lastTime += s * 8000 / f->b; + // if (tick - f->lastTime > 100) f->lastTime += (tick-f->lastTime-100) / + // 2; + // } // If we are more than a 10th of a second behind we reduce the + // bitrate. + // } - h->i = (f->e.i++); - f->userSend (f, h, s, 1, f->userData); + h->i = (f->e.i++); + f->userSend(f, h, s, 1, f->userData); } -#define i2redundant(i,k,v) ((i) + (k) % (v) >= (k) ? (i) % (v) + \ - (k) / (v) * (v) : (i) % (v) * ((k) / (v)) + (i) / (v)) +#define i2redundant(i, k, v) \ + ((i) + (k) % (v) >= (k) ? (i) % (v) + (k) / (v) * (v) \ + : (i) % (v) * ((k) / (v)) + (i) / (v)) /* This function is used to send the redundant packets in a permutated order, distributing the effects of bust losses. The weakness of this implementation is that the last k % v packets are not permutated. We choose v = w. @@ -144,32 +151,26 @@ static void SendWithDelay (fecPayload *buf, fec_encoder *f) */ - -void fec_encode (fecPayload *buf, fec_encoder *f) -{ +void fec_encode(fecPayload *buf, fec_encoder *f) { __int32_t i; - AddToRedundant (buf, &f->e, f->e.i); + AddToRedundant(buf, &f->e, f->e.i); - SendWithDelay (buf, f); + SendWithDelay(buf, f); if (f->e.i % (f->e.n + f->e.k) == f->e.n) { for (i = 0; i < f->e.k; i++) { - SendWithDelay ((fecPayload*) ( - i2redundant (i, f->e.k, f->e.w) * f->e.s + (char*)(f + 1)), f); + SendWithDelay((fecPayload *)(i2redundant(i, f->e.k, f->e.w) * f->e.s + + (char *)(f + 1)), + f); // To Do : Ensure that the lower CPU load at this point does not // create timing problems } } } -void delete_fec_encoder (fec_encoder *f) -{ - g_free (f); -} +void delete_fec_encoder(fec_encoder *f) { g_free(f); } - -fec_decoder *new_fec_decoder (void *userData, User_Recv recv) -{ - fec_decoder *f = (fec_decoder*)g_malloc (sizeof (*f)); +fec_decoder *new_fec_decoder(void *userData, User_Recv recv) { + fec_decoder *f = (fec_decoder *)g_malloc(sizeof(*f)); f->userData = userData; f->recv = recv; f->errorMessage = NULL; @@ -182,22 +183,21 @@ fec_decoder *new_fec_decoder (void *userData, User_Recv recv) return f; } -size_t fec_decode (void *buf, size_t size, size_t count, fec_decoder *f) -{ - Fec_Header *h = (Fec_Header*)buf; - __int32_t i, mustSend = 0, hi = (h->i); +size_t fec_decode(void *buf, size_t size, size_t count, fec_decoder *f) { + Fec_Header *h = (Fec_Header *)buf; + __int32_t i, mustSend = 0, hi = (h->i); if (!f->e) { - f->e = (fec_enc_dec*)calloc (1, sizeof (*f->e) + (size * count - sizeof (*h)) * - ( (h->kwg) & ((1 << KBITS) - 1))); - f->e->n = (h->n); - f->e->s = size * count - sizeof (*h); - f->e->k = (h->kwg) & ((1 << KBITS) - 1); - f->e->w = ( (h->kwg) >> KBITS) & ((1 << WBITS) - 1); - f->e->g = (h->kwg) >> (KBITS + WBITS); + f->e = (fec_enc_dec *)calloc(1, sizeof(*f->e) + + (size * count - sizeof(*h)) * + ((h->kwg) & ((1 << KBITS) - 1))); + f->e->n = (h->n); + f->e->s = size * count - sizeof(*h); + f->e->k = (h->kwg) & ((1 << KBITS) - 1); + f->e->w = ((h->kwg) >> KBITS) & ((1 << WBITS) - 1); + f->e->g = (h->kwg) >> (KBITS + WBITS); f->e->i = hi / (f->e->n + f->e->k) * (f->e->n + f->e->k); f->lostPackets += f->e->i; - } - else if ( (h->n) != f->e->n || size*count - sizeof (*h) != f->e->s) { + } else if ((h->n) != f->e->n || size * count - sizeof(*h) != f->e->s) { f->errorMessage = "Changing of FEC parameters not supported"; return 0; } @@ -206,14 +206,15 @@ size_t fec_decode (void *buf, size_t size, size_t count, fec_decoder *f) if (f->e->i <= hi) { // If we got it, or a later one mustSend = 1; do { - if (f->e->i % (f->e->n + f->e->k) == 0) flush_fec_decoder (f); + if (f->e->i % (f->e->n + f->e->k) == 0) + flush_fec_decoder(f); if (f->e->i < hi) { // If we got a later one, this one is marked as awol - f->missed = (fecPayload*)realloc (f->missed, (f->nmissed + 1) * sizeof (*f->missed)); + f->missed = (fecPayload *)realloc(f->missed, (f->nmissed + 1) * + sizeof(*f->missed)); f->missed[f->nmissed++] = f->e->i; } } while (++f->e->i <= hi); - } - else { + } else { for (i = f->nmissed - 1; i >= 0; i--) { if (f->missed[i] == hi) { // One of the awols showed up late f->nmissed--; @@ -226,15 +227,18 @@ size_t fec_decode (void *buf, size_t size, size_t count, fec_decoder *f) if (mustSend) { i = hi % (f->e->n + f->e->k) - f->e->n; if (i < 0) { - AddToRedundant ((fecPayload*) (h + 1), f->e, hi);\ + AddToRedundant((fecPayload *)(h + 1), f->e, hi); - f->recv(f, f->userData, (hi / (f->e->n + f->e->k) * f->e->n + - i + f->e->n) * (__int64_t) f->e->s, (fecPayload*)(h + 1), f->e->s); + f->recv(f, f->userData, + (hi / (f->e->n + f->e->k) * f->e->n + i + f->e->n) * + (__int64_t)f->e->s, + (fecPayload *)(h + 1), f->e->s); f->receivedPackets++; - } - else { - MAC (1, (fecPayload*) (h + 1), (fecPayload*)(i2redundant (i, f->e->k, - f->e->w) * f->e->s + (char*) (f->e + 1)), f->e->g, f->e->s); + } else { + MAC(1, (fecPayload *)(h + 1), + (fecPayload *)(i2redundant(i, f->e->k, f->e->w) * f->e->s + + (char *)(f->e + 1)), + f->e->g, f->e->s); } } @@ -243,13 +247,14 @@ size_t fec_decode (void *buf, size_t size, size_t count, fec_decoder *f) static __int32_t ew, ek; // To Do : make this code reentrant. -static __int32_t MissingCompare (const void *a, const void *b) -{ // One of the short comings of qsort - return * (__int32_t *) a * ew % ek - * (__int32_t *) b * ew % ek; +static __int32_t +MissingCompare(const void *a, + const void *b) { // One of the short comings of qsort + return *(__int32_t *)a * ew % ek - *(__int32_t *)b * ew % ek; } -#define BITS ((__int32_t) sizeof (__int32_t) * 8) // The # of columns stored in each *coef - +#define BITS \ + ((__int32_t)sizeof(__int32_t) * 8) // The # of columns stored in each *coef typedef struct { __int32_t start, len, pivotLog, *coef; @@ -260,47 +265,49 @@ typedef struct { fecPayload *redundant; } TMP_S; -void flush_fec_decoder (fec_decoder *f) -{ - TMP_S *r, **matrix, *best; +void flush_fec_decoder(fec_decoder *f) { + TMP_S *r, **matrix, *best; __int32_t i, tmp, row, mid, j, leader, bestLeader = 0, k, *GFlog, *GFexp; fecPayload *final; __uint32_t coef; #ifdef DEBUG_Z2 // This debugging / visualization code only works if g = 1. - FILE *sf = fopen ("sf.txt", "w"); // For a graphical representation. + FILE *sf = fopen("sf.txt", "w"); // For a graphical representation. #endif while (f->e->i % (f->e->n + f->e->k) != 0) { - f->missed = (fecPayload*)realloc (f->missed, (f->nmissed + 1) * sizeof (*f->missed)); + f->missed = + (fecPayload *)realloc(f->missed, (f->nmissed + 1) * sizeof(*f->missed)); f->missed[f->nmissed++] = f->e->i++; } - if (f->nmissed == 0) return; // This happens at startup + if (f->nmissed == 0) + return; // This happens at startup if (f->nmissed > f->e->k) { for (i = 0; i < f->nmissed; i++) { - if (f->missed[i] % (f->e->n + f->e->k) < f->e->n) f->lostPackets++; + if (f->missed[i] % (f->e->n + f->e->k) < f->e->n) + f->lostPackets++; } f->nmissed = 0; - g_free (f->missed); + g_free(f->missed); f->missed = NULL; return; } - r = (TMP_S*)malloc (sizeof (*r) * f->e->k); - matrix = (TMP_S**)malloc (sizeof (*matrix) * f->e->k); + r = (TMP_S *)malloc(sizeof(*r) * f->e->k); + matrix = (TMP_S **)malloc(sizeof(*matrix) * f->e->k); for (i = 0; i < f->e->k; i++) { r[i].coef = NULL; r[i].start = 0; r[i].len = 0; r[i].pivotLog = -1; - r[i].redundant = (fecPayload*) (i * f->e->s + (char*) (f->e + 1)); + r[i].redundant = (fecPayload *)(i * f->e->s + (char *)(f->e + 1)); matrix[i] = r + i; } for (i = f->nmissed - 1; i >= 0; i--) { tmp = f->missed[i] % (f->e->n + f->e->k) - f->e->n; if (tmp >= 0) { // Drop the redundants we don't have. - matrix[i2redundant (tmp, f->e->k, f->e->w)] = NULL; + matrix[i2redundant(tmp, f->e->k, f->e->w)] = NULL; f->missed[--f->nmissed] = f->missed[i]; } } @@ -308,40 +315,47 @@ void flush_fec_decoder (fec_decoder *f) // Now f->missed only contains the payload packets. ew = f->e->w; ek = f->e->k; - qsort (f->missed, f->nmissed, sizeof (*f->missed), MissingCompare); + qsort(f->missed, f->nmissed, sizeof(*f->missed), MissingCompare); // The sorting places all the nonzero entries in the matrix together. - for (i = 0; i < f->nmissed; i++) { // Build matrix + for (i = 0; i < f->nmissed; i++) { // Build matrix mid = f->missed[i] * f->e->w % f->e->k; // e.g. mid = i * 87654321 % e->k coef = f->missed[i] + 1; - for (row = max (0, min (mid, f->e->k - f->e->w) - f->e->w); - row < min (f->e->k, max (mid, f->e->w) + f->e->w); row++) { + for (row = max(0, min(mid, f->e->k - f->e->w) - f->e->w); + row < min(f->e->k, max(mid, f->e->w) + f->e->w); row++) { coef *= 1763689789; tmp = coef >> (32 - f->e->g); - if (tmp == 0 || !matrix[row]) continue; + if (tmp == 0 || !matrix[row]) + continue; if (r[row].start + r[row].len * BITS <= i) { // Need space ? - if (r[row].len == 0) r[row].start = i / BITS * BITS; - r[row].coef = (__int32_t*)realloc (r[row].coef, - (i + BITS - r[row].start) / BITS * f->e->g * sizeof (__int32_t)); - memset (r[row].coef + r[row].len * f->e->g, 0, f->e->g * sizeof (__int32_t) - * ((i - r[row].start) / BITS + 1 - r[row].len)); + if (r[row].len == 0) + r[row].start = i / BITS * BITS; + r[row].coef = + (__int32_t *)realloc(r[row].coef, (i + BITS - r[row].start) / BITS * + f->e->g * sizeof(__int32_t)); + memset(r[row].coef + r[row].len * f->e->g, 0, + f->e->g * sizeof(__int32_t) * + ((i - r[row].start) / BITS + 1 - r[row].len)); r[row].len = (i - r[row].start) / BITS + 1; } for (j = (i - r[row].start) / BITS * f->e->g; tmp > 0; j++, tmp >>= 1) { - if (tmp & 1) r[row].coef[j] ^= 1 << (i & (BITS - 1)); + if (tmp & 1) + r[row].coef[j] ^= 1 << (i & (BITS - 1)); } // Shift the bits into the matrix } // for each row. } // for each column // Work out the Galois field - GFexp = (__int32_t*)malloc (sizeof (*GFexp) * ((2 << f->e->g) - 2)); - GFlog = (__int32_t*)malloc (sizeof (*GFlog) * (1 << f->e->g)); + GFexp = (__int32_t *)malloc(sizeof(*GFexp) * ((2 << f->e->g) - 2)); + GFlog = (__int32_t *)malloc(sizeof(*GFlog) * (1 << f->e->g)); for (i = 0, tmp = 1; i < (2 << f->e->g) - 2; i++) { GFexp[i] = tmp; - if (i < (1 << f->e->g) - 1) GFlog[tmp] = i; + if (i < (1 << f->e->g) - 1) + GFlog[tmp] = i; tmp <<= 1; - if (tmp >> f->e->g) tmp ^= poly[f->e->g]; + if (tmp >> f->e->g) + tmp ^= poly[f->e->g]; } // Now the slow bit : creating the pivots rows @@ -351,55 +365,63 @@ void flush_fec_decoder (fec_decoder *f) for (i = 0; i < f->nmissed;) { #ifdef DEBUG_Z2 for (row = 0; row < f->e->k; row++) { - best = matrix[row];//r + row; + best = matrix[row]; // r + row; for (j = k = 0; j < f->nmissed; j++) { tmp = best->start <= j && j < best->start + BITS * best->len && - ((best->coef[(j - best->start)/BITS] >> (j & (BITS - 1))) & 1); - fputc (tmp ? '*' : ' ', sf); - if (tmp) k ^= f->missed[j] * 4; + ((best->coef[(j - best->start) / BITS] >> (j & (BITS - 1))) & 1); + fputc(tmp ? '*' : ' ', sf); + if (tmp) + k ^= f->missed[j] * 4; } - fprintf (sf, k == best->redundant[0] ? "yes\n" : "no\n"); + fprintf(sf, k == best->redundant[0] ? "yes\n" : "no\n"); } - fprintf (sf, "Now trying to create a pivot in row %3d\n", i); + fprintf(sf, "Now trying to create a pivot in row %3d\n", i); #endif bestLeader = -1; // The leader is the first non zero element. for (row = i; row < f->e->k && bestLeader < i; row++) { - if (!matrix[row]) continue; - for (leader = 0; leader * BITS + matrix[row]->start <= i && - leader < matrix[row]->len; leader++) { + if (!matrix[row]) + continue; + for (leader = 0; + leader * BITS + matrix[row]->start <= i && leader < matrix[row]->len; + leader++) { for (j = k = 0; k < f->e->g; k++) { j |= matrix[row]->coef[leader * f->e->g + k]; } - if (j == 0) continue; // Row starts with 32 zeros - for (leader = leader * BITS + matrix[row]->start; !(j & 1); - leader++) j >>= 1; - if (leader > i || bestLeader >= i) break; // not a new best so break + if (j == 0) + continue; // Row starts with 32 zeros + for (leader = leader * BITS + matrix[row]->start; !(j & 1); leader++) + j >>= 1; + if (leader > i || bestLeader >= i) + break; // not a new best so break bestLeader = leader; tmp = row; break; // We worked out where the leader is. } } - if (bestLeader < 0) break; + if (bestLeader < 0) + break; best = matrix[tmp]; matrix[tmp] = matrix[i]; matrix[i] = best; // Now eliminate *best from bestLeader to i. - for (j = bestLeader; ; j++) { + for (j = bestLeader;; j++) { leader = 0; // If j = i we calculate leader before quiting the loop. if ((j - best->start) / BITS < best->len) { for (k = ((j - best->start) / BITS + 1) * f->e->g - 1; - k >= (j - best->start) / BITS * f->e->g; k--) { + k >= (j - best->start) / BITS * f->e->g; k--) { leader <<= 1; - if (best->coef[k] & (1 << (j & (BITS - 1)))) leader++; + if (best->coef[k] & (1 << (j & (BITS - 1)))) + leader++; } } - if (j >= i) break; // Bail out with "leader" the pivot - if (!leader) continue; // Multiplying with 0 has no effect - leader = GFexp[GFlog[leader] + (1<e->g) - 1 - - matrix[j]->pivotLog]; + if (j >= i) + break; // Bail out with "leader" the pivot + if (!leader) + continue; // Multiplying with 0 has no effect + leader = GFexp[GFlog[leader] + (1 << f->e->g) - 1 - matrix[j]->pivotLog]; // Now we want *best += best[j] / matrix[j]->pivot * matrix[j]. // Redundants are easy : - MAC (leader, matrix[j]->redundant, best->redundant, f->e->g, f->e->s); + MAC(leader, matrix[j]->redundant, best->redundant, f->e->g, f->e->s); // The matrix is itself more tricky : have to check for space first. // Note that with normal band matrices we can require that each @@ -407,65 +429,71 @@ void flush_fec_decoder (fec_decoder *f) // below would never excute. But this Gauss elimination is not normal, // and there is always a possibility that we may end up needing a // row that was put aside long ago. - k = matrix[j]->start / BITS + matrix[j]->len - - best->start / BITS - best->len; + k = matrix[j]->start / BITS + matrix[j]->len - best->start / BITS - + best->len; if (k > 0) { - best->coef = (__int32_t*)realloc (best->coef, - (best->len + k) * sizeof (best->coef[0]) * f->e->g); - memset (best->coef + best->len * f->e->g, 0, - k * f->e->g * sizeof (best->coef[0])); + best->coef = (__int32_t *)realloc( + best->coef, (best->len + k) * sizeof(best->coef[0]) * f->e->g); + memset(best->coef + best->len * f->e->g, 0, + k * f->e->g * sizeof(best->coef[0])); best->len += k; } - for (k = (j - matrix[j]->start) / BITS, - tmp = (j - best->start) / BITS; k < matrix[j]->len; k++, tmp++) { - MAC (leader, matrix[j]->coef + k * f->e->g, - best->coef + tmp * f->e->g, f->e->g, f->e->g * sizeof (__int32_t)); + for (k = (j - matrix[j]->start) / BITS, tmp = (j - best->start) / BITS; + k < matrix[j]->len; k++, tmp++) { + MAC(leader, matrix[j]->coef + k * f->e->g, best->coef + tmp * f->e->g, + f->e->g, f->e->g * sizeof(__int32_t)); } } // For each entry we eliminate - if (leader != 0) matrix[i++]->pivotLog = GFlog[leader]; + if (leader != 0) + matrix[i++]->pivotLog = GFlog[leader]; } // For each pivot we need - if (bestLeader < 0) f->lostPackets += f->nmissed; + if (bestLeader < 0) + f->lostPackets += f->nmissed; else { // Let's do back substitution f->correctedPackets += f->nmissed; - final = (fecPayload*)malloc (f->e->s); + final = (fecPayload *)malloc(f->e->s); for (i = f->nmissed - 1; i >= 0; i--) { - memset (final, 0, f->e->s); - MAC (GFexp[(1<e->g) - 1 - matrix[i]->pivotLog], - matrix[i]->redundant, final, f->e->g, f->e->s); + memset(final, 0, f->e->s); + MAC(GFexp[(1 << f->e->g) - 1 - matrix[i]->pivotLog], matrix[i]->redundant, + final, f->e->g, f->e->s); // Now that we have final, we may as well back substitute into all for (j = 0; j < i; j++) { // the rows above k = (i - matrix[j]->start) / BITS; - if (k >= matrix[j]->len) continue; + if (k >= matrix[j]->len) + continue; for (leader = 0, tmp = f->e->g - 1; tmp >= 0; tmp--) { - leader = (leader << 1) + (1 & ( - matrix[j]->coef[k * f->e->g + tmp] >> (i & (BITS - 1)))); + leader = (leader << 1) + (1 & (matrix[j]->coef[k * f->e->g + tmp] >> + (i & (BITS - 1)))); } // We call MAC, even if leader is 0. Is it inefficient ? - MAC (leader, final, matrix[j]->redundant, f->e->g, f->e->s); + MAC(leader, final, matrix[j]->redundant, f->e->g, f->e->s); } f->recv(f, f->userData, - (f->missed[i] / (f->e->n + f->e->k) * f->e->n + f->missed[i] % - (f->e->n + f->e->k)) * (__int64_t) f->e->s, final, f->e->s); + (f->missed[i] / (f->e->n + f->e->k) * f->e->n + + f->missed[i] % (f->e->n + f->e->k)) * + (__int64_t)f->e->s, + final, f->e->s); } - g_free (final); + g_free(final); } #ifdef DEBUG_Z2 - fclose (sf); + fclose(sf); #endif - - g_free (GFlog); - g_free (GFexp); - for (i = 0; i < f->e->k; i++) g_free (r[i].coef); - g_free (matrix); - g_free (f->missed); + + g_free(GFlog); + g_free(GFexp); + for (i = 0; i < f->e->k; i++) + g_free(r[i].coef); + g_free(matrix); + g_free(f->missed); f->missed = NULL; f->nmissed = 0; - g_free (r); + g_free(r); } -void delete_fec_decoder (fec_decoder *f) -{ - if (f) g_free (f->e); // free(NULL) is valid. - g_free (f); +void delete_fec_decoder(fec_decoder *f) { + if (f) + g_free(f->e); // free(NULL) is valid. + g_free(f); } diff --git a/Core/transmit_protocol/feclib/fec.h b/Core/transmit_protocol/feclib/fec.h index 258d1af..31e07cf 100644 --- a/Core/transmit_protocol/feclib/fec.h +++ b/Core/transmit_protocol/feclib/fec.h @@ -2,20 +2,16 @@ #define FEC_COPYRIGHT "Parts copyright (c) by Nic Roets 2002. No warranty." #include - -#define SUGGESTED_FEC_UDP_PORT_NUMBER htons (7837) +#define SUGGESTED_FEC_UDP_PORT_NUMBER htons(7837) // This is just a suggestion. If you modify the protocol, please use a // different port. #include "../core/main.h" - - #ifdef __cplusplus extern "C" { #endif - #define __int64_t IINT64 #define __int32_t IINT32 #define __uint32_t IUINT32 @@ -33,9 +29,10 @@ typedef struct headerStruct { #endif typedef struct fec_encoder fec_encoder; typedef struct fec_decoder fec_decoder; -typedef void (*User_Recv)(fec_decoder* dec, void *userData, __int64_t position, fecPayload *buf, __int32_t len); -typedef size_t (*User_Send)(fec_encoder *enc, void *buf, size_t size, size_t count, void *userData); - +typedef void (*User_Recv)(fec_decoder *dec, void *userData, __int64_t position, + fecPayload *buf, __int32_t len); +typedef size_t (*User_Send)(fec_encoder *enc, void *buf, size_t size, + size_t count, void *userData); typedef struct { __int32_t k, w, g, n, i, s; @@ -48,18 +45,17 @@ struct fec_encoder { fec_enc_dec e; }; -fec_encoder *new_fec_encoder (void *userData, - User_Send userSend, - char **errorMessage, - __int32_t s, __int32_t n, __int32_t k, __int32_t w, __int32_t g, __int32_t b); +fec_encoder *new_fec_encoder(void *userData, User_Send userSend, + char **errorMessage, __int32_t s, __int32_t n, + __int32_t k, __int32_t w, __int32_t g, + __int32_t b); -void fec_encode (fecPayload *buf, fec_encoder *f); +void fec_encode(fecPayload *buf, fec_encoder *f); -void delete_fec_encoder (fec_encoder *f); +void delete_fec_encoder(fec_encoder *f); //----------------------------------------- - struct fec_decoder { __int32_t lostPackets, receivedPackets, correctedPackets; // payload only char *errorMessage; @@ -71,14 +67,13 @@ struct fec_decoder { fecPayload *missed; // Keeps track of both payload and redundant packets. }; -fec_decoder *new_fec_decoder (void *userData, User_Recv recv); +fec_decoder *new_fec_decoder(void *userData, User_Recv recv); -size_t fec_decode (void *buf, size_t size, size_t count, - fec_decoder *f); +size_t fec_decode(void *buf, size_t size, size_t count, fec_decoder *f); -void flush_fec_decoder (fec_decoder *f); +void flush_fec_decoder(fec_decoder *f); -void delete_fec_decoder (fec_decoder *f); +void delete_fec_decoder(fec_decoder *f); #ifdef __cplusplus } diff --git a/Core/transmit_protocol/feclib/index.html b/Core/transmit_protocol/feclib/index.html index f246110..62bd871 100644 --- a/Core/transmit_protocol/feclib/index.html +++ b/Core/transmit_protocol/feclib/index.html @@ -1,32 +1,34 @@ - +
-Project Summary - - -Current Version (WebCVS) - -API documentation +
+ Project Summary + + + Current Version (WebCVS) + + API documentation

-SourceForge.net Logo + SourceForge.net Logo

Welcome to the Forword Error Correction Library !

At the insistence of my good friend, Edwin Peer, (and his assistant, Johnny), I've spent a few weeks designing and coding this open source encoder and decoder, and the project is currently at its first public release.

Frequently Asked Questions

    -
  1. Why should I use this library, when others are more mature, or come -with commercial support etc ? Firstly this library is very clean, -making -it very easy to maintain, port etc. There can't be many bugs left in the mere -500 lines of code. Secondly, this library is much more configurable. -
  2. How does it work ? Click here -for a lay man's description. -
  3. Can I use this library to locate and correct communications -errors ? No. This library cannot detect or correct data that has been -changed. Rather look at projects like -RSCode. +
  4. Why should I use this library, when others are more mature, or come + with commercial support etc ? Firstly this library is very clean, + making + it very easy to maintain, port etc. There can't be many bugs left in the mere + 500 lines of code. Secondly, this library is much more configurable. +
  5. How does it work ? Click here + for a lay man's description. +
  6. Can I use this library to locate and correct communications + errors ? No. This library cannot detect or correct data that has been + changed. Rather look at projects like + RSCode.

Downloads - also available with Source Forge Release

feclib-0.90.tar.gz
diff --git a/Core/transmit_protocol/global.cpp b/Core/transmit_protocol/global.cpp index 3e69513..55257dd 100644 --- a/Core/transmit_protocol/global.cpp +++ b/Core/transmit_protocol/global.cpp @@ -1,6 +1,5 @@ #include "global.h" - #ifdef _WIN32 #include "../system/windows_include.h" #else @@ -10,75 +9,76 @@ #include IUINT16 rand_range_16(IUINT16 min, IUINT16 max) { - if (min > max) { - // 如果参数传反了,交换 - IUINT16 temp = min; - min = max; - max = temp; - } - return min + rand() % (max - min + 1); + if (min > max) { + // 如果参数传反了,交换 + IUINT16 temp = min; + min = max; + max = temp; + } + return min + rand() % (max - min + 1); } -void itimeofday(long *sec, long *usec) -{ +void itimeofday(long *sec, long *usec) { #if defined(__unix) - struct timeval time; - gettimeofday(&time, NULL); - if (sec) *sec = time.tv_sec; - if (usec) *usec = time.tv_usec; + struct timeval time; + gettimeofday(&time, NULL); + if (sec) + *sec = time.tv_sec; + if (usec) + *usec = time.tv_usec; #else - static long mode = 0, addsec = 0; - BOOL retval; - static IINT64 freq = 1; - IINT64 qpc; - if (mode == 0) { - retval = QueryPerformanceFrequency((LARGE_INTEGER*)&freq); - freq = (freq == 0)? 1 : freq; - retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc); - addsec = (long)time(NULL); - addsec = addsec - (long)((qpc / freq) & 0x7fffffff); - mode = 1; - } - retval = QueryPerformanceCounter((LARGE_INTEGER*)&qpc); - retval = retval * 2; - if (sec) *sec = (long)(qpc / freq) + addsec; - if (usec) *usec = (long)((qpc % freq) * 1000000 / freq); + static long mode = 0, addsec = 0; + BOOL retval; + static IINT64 freq = 1; + IINT64 qpc; + if (mode == 0) { + retval = QueryPerformanceFrequency((LARGE_INTEGER *)&freq); + freq = (freq == 0) ? 1 : freq; + retval = QueryPerformanceCounter((LARGE_INTEGER *)&qpc); + addsec = (long)time(NULL); + addsec = addsec - (long)((qpc / freq) & 0x7fffffff); + mode = 1; + } + retval = QueryPerformanceCounter((LARGE_INTEGER *)&qpc); + retval = retval * 2; + if (sec) + *sec = (long)(qpc / freq) + addsec; + if (usec) + *usec = (long)((qpc % freq) * 1000000 / freq); #endif } /* get clock in millisecond 64 */ -IINT64 iclock64(void) -{ - long s, u; - IINT64 value; - itimeofday(&s, &u); - value = ((IINT64)s) * 1000 + (u / 1000); - return value; +IINT64 iclock64(void) { + long s, u; + IINT64 value; + itimeofday(&s, &u); + value = ((IINT64)s) * 1000 + (u / 1000); + return value; } -IUINT32 iclock() -{ - return (IUINT32)(iclock64() & 0xfffffffful); -} +IUINT32 iclock() { return (IUINT32)(iclock64() & 0xfffffffful); } int check_cycle_0_9(const char *str, int len) { - if (len <= 0) return false; + if (len <= 0) + return false; - for (int i = 1; i < len; i++) { - // 上一个字符 - char prev = str[i - 1]; - char expected = (prev == '9') ? '0' : prev + 1; + for (int i = 1; i < len; i++) { + // 上一个字符 + char prev = str[i - 1]; + char expected = (prev == '9') ? '0' : prev + 1; - if (str[i] != expected) { - return i; - } + if (str[i] != expected) { + return i; } - return 0; + } + return 0; } -void print_hex(const char* prefix, const uint8_t* data, int len, const char* suffix) { - printf("%s", prefix); - for (int i = 0; i < len; ++i) { - printf("%02X ", data[i]); // %02X: 打印两位十六进制数,前面补零,X为大写字母 - } - printf("%s", suffix); +void print_hex(const char *prefix, const uint8_t *data, int len, + const char *suffix) { + printf("%s", prefix); + for (int i = 0; i < len; ++i) { + printf("%02X ", data[i]); // %02X: 打印两位十六进制数,前面补零,X为大写字母 + } + printf("%s", suffix); } diff --git a/Core/transmit_protocol/global_tree.cpp b/Core/transmit_protocol/global_tree.cpp index 05e147e..3dca3e4 100644 --- a/Core/transmit_protocol/global_tree.cpp +++ b/Core/transmit_protocol/global_tree.cpp @@ -1,281 +1,269 @@ +#include "global.h" #include #include -#include "global.h" // TODO: 多叉树型结构 // init 的时候 缓存执行列表的 正序 反序 // 这样监控节点能监控 协议的任意一部分 +typedef void (*Handle_Node)(Proto_Tree_Node *); -typedef void (*Handle_Node)(Proto_Tree_Node*); - - - -void Node_List_Append(Node_List* list, Proto_Tree_Node* node) { - if (list->head == nullptr) { - list->head = list->tail = node; - } else { - list->tail->next = node; - node->prev = list->tail; - list->tail = node; - } +void Node_List_Append(Node_List *list, Proto_Tree_Node *node) { + if (list->head == nullptr) { + list->head = list->tail = node; + } else { + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + } } -void Node_List_Prepend(Node_List* list, Proto_Tree_Node* node) { - if (list->head == nullptr) { - list->head = list->tail = node; - } else { - node->next = list->head; - list->head->prev = node; - list->head = node; - } +void Node_List_Prepend(Node_List *list, Proto_Tree_Node *node) { + if (list->head == nullptr) { + list->head = list->tail = node; + } else { + node->next = list->head; + list->head->prev = node; + list->head = node; + } } -void Node_List_Traverse(Node_List* list, Handle_Node handler) { - Proto_Tree_Node* cur = list->head; - while (cur) { - Proto_Tree_Node* next = cur->next; - handler(cur); - cur = next; - } +void Node_List_Traverse(Node_List *list, Handle_Node handler) { + Proto_Tree_Node *cur = list->head; + while (cur) { + Proto_Tree_Node *next = cur->next; + handler(cur); + cur = next; + } } - -Cache_List_Node* create_Cache_List_Node(Proto_Tree_Node* d) { - auto node = (Cache_List_Node*)g_malloc(sizeof(Cache_List_Node)); - node->tn = d; - node->next = node->prev = nullptr; - return node; +Cache_List_Node *create_Cache_List_Node(Proto_Tree_Node *d) { + auto node = (Cache_List_Node *)g_malloc(sizeof(Cache_List_Node)); + node->tn = d; + node->next = node->prev = nullptr; + return node; } -void Cache_List_Append(Cache_List* list, Cache_List_Node* node) { - if (list->head == nullptr) { - list->head = list->tail = node; - } else { - list->tail->next = node; - node->prev = list->tail; - list->tail = node; - } +void Cache_List_Append(Cache_List *list, Cache_List_Node *node) { + if (list->head == nullptr) { + list->head = list->tail = node; + } else { + list->tail->next = node; + node->prev = list->tail; + list->tail = node; + } } -void Cache_List_Prepend(Cache_List* list, Cache_List_Node* node) { - if (list->head == nullptr) { - list->head = list->tail = node; - } else { - node->next = list->head; - list->head->prev = node; - list->head = node; - } +void Cache_List_Prepend(Cache_List *list, Cache_List_Node *node) { + if (list->head == nullptr) { + list->head = list->tail = node; + } else { + node->next = list->head; + list->head->prev = node; + list->head = node; + } } -void Cache_List_release(Cache_List* list) { - Cache_List_Node* cur = list->head; - while (cur) { - Cache_List_Node* next = cur->next; - g_free(cur); // 只释放 Cache_List_Node,自身不释放 d - cur = next; - } - list->head = nullptr; - list->tail = nullptr; +void Cache_List_release(Cache_List *list) { + Cache_List_Node *cur = list->head; + while (cur) { + Cache_List_Node *next = cur->next; + g_free(cur); // 只释放 Cache_List_Node,自身不释放 d + cur = next; + } + list->head = nullptr; + list->tail = nullptr; } - - - -Proto_Tree_Node* Proto_Tree::append(Proto_Tree_Node* par, Base_CB* cb) { - auto node = new Proto_Tree_Node(cb); - node->tr = this; - if (par != nullptr) { - node->parent = par; - Node_List_Append(&par->children, node); - } else { - node->parent = nullptr; - Node_List_Append(&children, node); - } - return node; +Proto_Tree_Node *Proto_Tree::append(Proto_Tree_Node *par, Base_CB *cb) { + auto node = new Proto_Tree_Node(cb); + node->tr = this; + if (par != nullptr) { + node->parent = par; + Node_List_Append(&par->children, node); + } else { + node->parent = nullptr; + Node_List_Append(&children, node); + } + return node; } -Proto_Tree_Node* Proto_Tree::prepend(Proto_Tree_Node* par, Base_CB* cb) { - auto node = new Proto_Tree_Node(cb); - node->tr = this; - if (par != nullptr) { - node->parent = par; - Node_List_Prepend(&par->children, node); - } else { - node->parent = nullptr; - Node_List_Prepend(&children, node); - } - return node; +Proto_Tree_Node *Proto_Tree::prepend(Proto_Tree_Node *par, Base_CB *cb) { + auto node = new Proto_Tree_Node(cb); + node->tr = this; + if (par != nullptr) { + node->parent = par; + Node_List_Prepend(&par->children, node); + } else { + node->parent = nullptr; + Node_List_Prepend(&children, node); + } + return node; } - -Proto_Tree_Node::Proto_Tree_Node(Base_CB* cb) { - this->cb = cb; -} +Proto_Tree_Node::Proto_Tree_Node(Base_CB *cb) { this->cb = cb; } Proto_Tree_Node::~Proto_Tree_Node() { delete cb; } -typedef void (*Handle_Tree_Node)(Proto_Tree*, Proto_Tree_Node*, void* user, IUINT8 deep); -void Proto_Tree_Traverse_inter(Proto_Tree* tr, Proto_Tree_Node* node, Handle_Tree_Node handler, void* user, IUINT8 deep) { - if (node == nullptr) return; - Proto_Tree_Node* child = node->children.head; - handler(tr, node, user, deep); - while (child) { - Proto_Tree_Traverse_inter(tr, child, handler, user, ++deep); - child = child->next; - } +typedef void (*Handle_Tree_Node)(Proto_Tree *, Proto_Tree_Node *, void *user, + IUINT8 deep); +void Proto_Tree_Traverse_inter(Proto_Tree *tr, Proto_Tree_Node *node, + Handle_Tree_Node handler, void *user, + IUINT8 deep) { + if (node == nullptr) + return; + Proto_Tree_Node *child = node->children.head; + handler(tr, node, user, deep); + while (child) { + Proto_Tree_Traverse_inter(tr, child, handler, user, ++deep); + child = child->next; + } } -void Proto_Tree_Traverse(Proto_Tree* tr, Handle_Tree_Node handler, void* user) { - Proto_Tree_Node* cur = tr->children.head; - while (cur) { - Proto_Tree_Node* next = cur->next; - Proto_Tree_Traverse_inter(tr, cur, handler, user, 0); - cur = next; - } +void Proto_Tree_Traverse(Proto_Tree *tr, Handle_Tree_Node handler, void *user) { + Proto_Tree_Node *cur = tr->children.head; + while (cur) { + Proto_Tree_Node *next = cur->next; + Proto_Tree_Traverse_inter(tr, cur, handler, user, 0); + cur = next; + } } Proto_Tree::Proto_Tree() = default; - - - Proto_Tree::~Proto_Tree() { - Cache_List_release(&cache_list); - Ptr_List* pl = Ptr_List_new(nullptr); - Proto_Tree_Traverse( - this, - [](Proto_Tree* tr, Proto_Tree_Node* node, void* user, IUINT8 deep) { - auto pl = (Ptr_List*)user; - Ptr_List_append(pl, node); - }, - pl); - Ptr_Node* cur = pl->head; - while (cur) { - Ptr_Node* next = cur->next; - auto node = (Proto_Tree_Node*)cur->ptr; - delete node; - cur = next; - } - Ptr_List_delete(pl); + Cache_List_release(&cache_list); + Ptr_List *pl = Ptr_List_new(nullptr); + Proto_Tree_Traverse( + this, + [](Proto_Tree *tr, Proto_Tree_Node *node, void *user, IUINT8 deep) { + auto pl = (Ptr_List *)user; + Ptr_List_append(pl, node); + }, + pl); + Ptr_Node *cur = pl->head; + while (cur) { + Ptr_Node *next = cur->next; + auto node = (Proto_Tree_Node *)cur->ptr; + delete node; + cur = next; + } + Ptr_List_delete(pl); } - void Proto_Tree::send(Buf_Type buf, Len_Type len) { - // if (!cache_list.head) { - // if (pack_send) { - // pack_send(this, buf, len); - // } - // return; - // } - if (true_send) { - true_send(this, buf, len, user); - } - Proto_Tree_Node* first = cache_list.head->tn; - first->cb->send(buf, len, cache_list.head); + // if (!cache_list.head) { + // if (pack_send) { + // pack_send(this, buf, len); + // } + // return; + // } + if (true_send) { + true_send(this, buf, len, user); + } + Proto_Tree_Node *first = cache_list.head->tn; + first->cb->send(buf, len, cache_list.head); } - void Proto_Tree::recv(Buf_Type buf, Len_Type len) { - // if (!cache_list.tail) { - // if (true_recv) { - // true_recv(this, buf, len); - // } - // return; - // } - if (pack_recv) { - pack_recv(this, buf, len, user); - } - Proto_Tree_Node* last = cache_list.tail->tn; - last->cb->recv(buf, len, cache_list.tail); + // if (!cache_list.tail) { + // if (true_recv) { + // true_recv(this, buf, len); + // } + // return; + // } + if (pack_recv) { + pack_recv(this, buf, len, user); + } + Proto_Tree_Node *last = cache_list.tail->tn; + last->cb->recv(buf, len, cache_list.tail); } - - void Proto_Tree::print_state_info() { - Proto_Tree_Traverse( - this, [](Proto_Tree* tr, Proto_Tree_Node* node, void* user, IUINT8 deep) { node->cb->print_state_info(); }, - nullptr); + Proto_Tree_Traverse( + this, + [](Proto_Tree *tr, Proto_Tree_Node *node, void *user, IUINT8 deep) { + node->cb->print_state_info(); + }, + nullptr); } - - - // 协议发送协议接收 +void send_call_back(Base_CB *cb, Buf_Type buf, Len_Type len, void *user) { + auto t = static_cast(user); + Cache_List_Node *pn = t->next; + Proto_Tree_Node *node = t->tn; + Proto_Tree *tr = node->tr; + Proto_Tree_Node *par = node->parent; -void send_call_back(Base_CB* cb, Buf_Type buf, Len_Type len, void* user) { - auto t = static_cast(user); - Cache_List_Node* pn = t->next; - Proto_Tree_Node* node = t->tn; - Proto_Tree* tr = node->tr; - Proto_Tree_Node* par = node->parent; + if (node->children.head == nullptr) { + if (node->true_send) + node->true_send(node, buf, len); + if (node->pack_send) + node->pack_send(node, buf, len); + } - if (node->children.head == nullptr) { - if (node->true_send) node->true_send(node, buf, len); - if (node->pack_send) node->pack_send(node, buf, len); + if (par != nullptr) { + if (node->prev == nullptr) { + if (par->true_send) { + par->true_send(par, buf, len); + } } - - if (par != nullptr) { - if (node->prev == nullptr) { - if (par->true_send) { - par->true_send(par, buf, len); - } - } - if (node->next == nullptr) { - if (par->pack_send) { - par->pack_send(par, buf, len); - } - } + if (node->next == nullptr) { + if (par->pack_send) { + par->pack_send(par, buf, len); + } } - if (pn == nullptr) { - if (tr->pack_send) { - tr->pack_send(tr, buf, len, user); - } - return; + } + if (pn == nullptr) { + if (tr->pack_send) { + tr->pack_send(tr, buf, len, user); } - pn->tn->cb->send(buf, len, pn); + return; + } + pn->tn->cb->send(buf, len, pn); } -void recv_call_back(Base_CB* cb, Buf_Type buf, Len_Type len, void* user) { - auto t = (Cache_List_Node*)user; - Cache_List_Node* pn = t->prev; - Proto_Tree_Node* node = t->tn; - Proto_Tree* tr = node->tr; - Proto_Tree_Node* par = node->parent; - if (node->children.head == nullptr) { - if (node->true_recv) node->true_recv(node, buf, len); - if (node->pack_recv) node->pack_recv(node, buf, len); +void recv_call_back(Base_CB *cb, Buf_Type buf, Len_Type len, void *user) { + auto t = (Cache_List_Node *)user; + Cache_List_Node *pn = t->prev; + Proto_Tree_Node *node = t->tn; + Proto_Tree *tr = node->tr; + Proto_Tree_Node *par = node->parent; + if (node->children.head == nullptr) { + if (node->true_recv) + node->true_recv(node, buf, len); + if (node->pack_recv) + node->pack_recv(node, buf, len); + } + if (par != nullptr) { + if (node->prev == nullptr) { + if (par->true_recv) { + par->true_recv(par, buf, len); + } } - if (par != nullptr) { - if (node->prev == nullptr) { - if (par->true_recv) { - par->true_recv(par, buf, len); - } - } - if (node->next == nullptr) { - if (par->pack_recv) { - par->pack_recv(par, buf, len); - } - } + if (node->next == nullptr) { + if (par->pack_recv) { + par->pack_recv(par, buf, len); + } } - if (pn == nullptr) { - if (tr->true_recv) { - tr->true_recv(tr, buf, len, user); - } - return; + } + if (pn == nullptr) { + if (tr->true_recv) { + tr->true_recv(tr, buf, len, user); } - pn->tn->cb->recv(buf, len, pn); + return; + } + pn->tn->cb->recv(buf, len, pn); } - - void Proto_Tree::create() { - Proto_Tree_Traverse( - this, - [](Proto_Tree* tr, Proto_Tree_Node* node, void* user, IUINT8 deep) { - Base_CB* cb = node->cb; - node->deep = deep; - cb->next_recv = recv_call_back; - cb->next_send = send_call_back; - Cache_List_Node* pn = create_Cache_List_Node(node); - cb->pn = pn; - cb->final_init(); - Cache_List_Append(&tr->cache_list, pn); - }, - nullptr); + Proto_Tree_Traverse( + this, + [](Proto_Tree *tr, Proto_Tree_Node *node, void *user, IUINT8 deep) { + Base_CB *cb = node->cb; + node->deep = deep; + cb->next_recv = recv_call_back; + cb->next_send = send_call_back; + Cache_List_Node *pn = create_Cache_List_Node(node); + cb->pn = pn; + cb->final_init(); + Cache_List_Append(&tr->cache_list, pn); + }, + nullptr); } \ No newline at end of file diff --git a/Core/transmit_protocol/kfec/FEC_CB.h b/Core/transmit_protocol/kfec/FEC_CB.h index b9ee637..9805123 100644 --- a/Core/transmit_protocol/kfec/FEC_CB.h +++ b/Core/transmit_protocol/kfec/FEC_CB.h @@ -9,27 +9,28 @@ // 但是后续发现实现可靠需要做到的太多, // 首先必然失去顺序保证(重发包带来的影响) // 其次丢掉的包反复重传,ack,nack 信令的可靠性要单独做保证 -// 缓存接收队列也要做 为了防止一个包卡住所有其他包,其他包要给这个包的ack信令做退让,那么流量控制机制也就需要 +// 缓存接收队列也要做 +// 为了防止一个包卡住所有其他包,其他包要给这个包的ack信令做退让,那么流量控制机制也就需要 // 所以实现复杂 暂时分出来 -namespace Psc{ +namespace Psc { struct FEC_CB : Base_CB { - // 发送端 - Packet_Seq_Type send_seq = 0; - Packet_Seq_Type recv_seq = 0; // 当前已经成功接收的packet 不包括recv_seq - Recv_FEC_Frame *cur_decode_frame{}; - Ptr_List* snd_buf{}; - Ptr_List* rcv_buf{}; - Ptr_List* order_buf{}; - Get_Millisecond get_millisecond{}; - Value_Statistics single_recv_success_rate{}; // 单包接收的成功率 - Probability_Statistics recover_success_rate{}; // 总体恢复的成功率 - Probability_Statistics recv_success_rate{}; // 总体的成功率 - ~FEC_CB() override; - explicit FEC_CB(Get_Millisecond get_millisecond); - void send(Buf_Type buf, Len_Type len, void* user) override; - void recv(Buf_Type buf, Len_Type len, void* user) override; + // 发送端 + Packet_Seq_Type send_seq = 0; + Packet_Seq_Type recv_seq = 0; // 当前已经成功接收的packet 不包括recv_seq + Recv_FEC_Frame *cur_decode_frame{}; + Ptr_List *snd_buf{}; + Ptr_List *rcv_buf{}; + Ptr_List *order_buf{}; + Get_Millisecond get_millisecond{}; + Value_Statistics single_recv_success_rate{}; // 单包接收的成功率 + Probability_Statistics recover_success_rate{}; // 总体恢复的成功率 + Probability_Statistics recv_success_rate{}; // 总体的成功率 + ~FEC_CB() override; + explicit FEC_CB(Get_Millisecond get_millisecond); + void send(Buf_Type buf, Len_Type len, void *user) override; + void recv(Buf_Type buf, Len_Type len, void *user) override; }; // 无用函数 仅仅用于测试 diff --git a/Core/transmit_protocol/kfec/Send_FEC_Frame.h b/Core/transmit_protocol/kfec/Send_FEC_Frame.h index b2aaf3a..9919712 100644 --- a/Core/transmit_protocol/kfec/Send_FEC_Frame.h +++ b/Core/transmit_protocol/kfec/Send_FEC_Frame.h @@ -1,6 +1,5 @@ #pragma once - #include "global.h" // 缓存的发送帧 这里的帧是完整的帧 @@ -8,16 +7,17 @@ namespace Psc { struct Send_FEC_Frame { IUINT16 s, n, k, last_s, total_len; - //DL* send_data_list; + // DL* send_data_list; IUINT16 cur_write_pos; FEC_Data_Packet header; Packet_Seq_Type seq; - char* buffer; + char *buffer; }; +Send_FEC_Frame *Cache_Send_Frame_create(Packet_Seq_Type seq, Buf_Type buf, + Len_Type len); +void Cache_Send_Frame_release(void *frame); +void Cache_Send_Frame_send(FEC_CB *cb, Send_FEC_Frame *frame, + void *user); // 发送帧 -Send_FEC_Frame* Cache_Send_Frame_create(Packet_Seq_Type seq, Buf_Type buf, Len_Type len); -void Cache_Send_Frame_release(void* frame); -void Cache_Send_Frame_send(FEC_CB* cb, Send_FEC_Frame* frame, void* user); // 发送帧 - -} +} // namespace Psc diff --git a/Core/transmit_protocol/kfec/global.cpp b/Core/transmit_protocol/kfec/global.cpp index de32633..1e6cc60 100644 --- a/Core/transmit_protocol/kfec/global.cpp +++ b/Core/transmit_protocol/kfec/global.cpp @@ -1,21 +1,19 @@ #include "global.h" #include "FEC_CB.h" - - namespace Psc { const Len_Type FEC_Data_Packet_len = sizeof(FEC_Data_Packet); const Len_Type Fec_Header_len = sizeof(Fec_Header); -void send_FEC_Send_Ask_lose_data(FEC_CB* cb, Recv_FEC_Frame* f) { +void send_FEC_Send_Ask_lose_data(FEC_CB *cb, Recv_FEC_Frame *f) { IUINT16 hl = sizeof(FEC_Send_Ask_lose_data); - Len_Type num = f->n + f->k; - FEC_Send_Ask_lose_data* d = (FEC_Send_Ask_lose_data*)g_malloc(hl + num); + Len_Type num = f->n + f->k; + FEC_Send_Ask_lose_data *d = (FEC_Send_Ask_lose_data *)g_malloc(hl + num); d->type = FEC_CB_Ask_lose_data; d->lose_rate = 1.0 - cb->single_recv_success_rate.average; d->seq = f->seq; d->resend_times = f->failed_times; - memmove((char*)d + sizeof(FEC_Send_Ask_lose_data), f->ok_buffer, num); - cb->next_send((Base_CB*)cb, (Buf_Type)d, hl + num, cb->pn); + memmove((char *)d + sizeof(FEC_Send_Ask_lose_data), f->ok_buffer, num); + cb->next_send((Base_CB *)cb, (Buf_Type)d, hl + num, cb->pn); g_free(d); } } \ No newline at end of file diff --git a/Core/transmit_protocol/other_node/Empty_Transmit.cpp b/Core/transmit_protocol/other_node/Empty_Transmit.cpp index 3d9f747..8a08351 100644 --- a/Core/transmit_protocol/other_node/Empty_Transmit.cpp +++ b/Core/transmit_protocol/other_node/Empty_Transmit.cpp @@ -1,11 +1,11 @@ #include "Empty_Transmit.h" -void Empty_Transmit_recv(Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { - Empty_Transmit_CB* cb = (Empty_Transmit_CB*)bcb; - bcb->next_recv(bcb, buf, len, user); +void Empty_Transmit_recv(Base_CB *bcb, Buf_Type buf, Len_Type len, void *user) { + Empty_Transmit_CB *cb = (Empty_Transmit_CB *)bcb; + bcb->next_recv(bcb, buf, len, user); } -void Empty_Transmit_send(Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { - Empty_Transmit_CB* cb = (Empty_Transmit_CB*)bcb; - bcb->next_send(bcb, buf, len, user); +void Empty_Transmit_send(Base_CB *bcb, Buf_Type buf, Len_Type len, void *user) { + Empty_Transmit_CB *cb = (Empty_Transmit_CB *)bcb; + bcb->next_send(bcb, buf, len, user); } diff --git a/Core/transmit_protocol/other_node/Empty_Transmit.h b/Core/transmit_protocol/other_node/Empty_Transmit.h index cb81c4b..4e2c281 100644 --- a/Core/transmit_protocol/other_node/Empty_Transmit.h +++ b/Core/transmit_protocol/other_node/Empty_Transmit.h @@ -1,17 +1,15 @@ #pragma once - #include "../global.h" - struct Empty_Transmit_CB : Base_CB { - void send(Buf_Type buf, Len_Type len, void* user) override { - next_send(this, buf, len, user); - } - void recv(Buf_Type buf, Len_Type len, void* user) override { - next_recv(this, buf, len, user); - } + void send(Buf_Type buf, Len_Type len, void *user) override { + next_send(this, buf, len, user); + } + void recv(Buf_Type buf, Len_Type len, void *user) override { + next_recv(this, buf, len, user); + } }; -void Empty_Transmit_recv(Base_CB* bcb, Buf_Type buf, Len_Type len, void* user); -void Empty_Transmit_send(Base_CB* bcb, Buf_Type buf, Len_Type len, void* user); +void Empty_Transmit_recv(Base_CB *bcb, Buf_Type buf, Len_Type len, void *user); +void Empty_Transmit_send(Base_CB *bcb, Buf_Type buf, Len_Type len, void *user); diff --git a/Core/transmit_protocol/other_node/SRP_Fixed_CB.cpp b/Core/transmit_protocol/other_node/SRP_Fixed_CB.cpp index bd893b5..6951f97 100644 --- a/Core/transmit_protocol/other_node/SRP_Fixed_CB.cpp +++ b/Core/transmit_protocol/other_node/SRP_Fixed_CB.cpp @@ -9,317 +9,309 @@ namespace Psc { void test_SRP_Fixed_CB_While(Get_Millisecond get_millisecond) { - const Len_Type max_packet_len = 60; - auto s1 = create_default_SRP_Fixed_CB(max_packet_len); - auto s2 = create_default_SRP_Fixed_CB(max_packet_len); - Proto_Tree *t1 = create_single_test(s1, get_millisecond).tree; - Proto_Tree *t2 = create_single_test(s2, get_millisecond).tree; + const Len_Type max_packet_len = 60; + auto s1 = create_default_SRP_Fixed_CB(max_packet_len); + auto s2 = create_default_SRP_Fixed_CB(max_packet_len); + Proto_Tree *t1 = create_single_test(s1, get_millisecond).tree; + Proto_Tree *t2 = create_single_test(s2, get_millisecond).tree; + Flow_Channel_Simulator fcs(t1, t2, 0.00); + t1->pack_send = [&fcs](Proto_Tree *tr, Buf_Type buf, Len_Type len, + void *user) { fcs.send(tr, buf, len); }; + t2->pack_send = [&fcs](Proto_Tree *tr, Buf_Type buf, Len_Type len, + void *user) { fcs.send(tr, buf, len); }; - Flow_Channel_Simulator fcs(t1, t2, 0.00); - t1->pack_send = [&fcs](Proto_Tree *tr, Buf_Type buf, Len_Type len, void *user) { fcs.send(tr, buf, len); }; - t2->pack_send = [&fcs](Proto_Tree *tr, Buf_Type buf, Len_Type len, void *user) { fcs.send(tr, buf, len); }; - - Len_Type buf_len = 10 * max_packet_len; - auto buf = new char[buf_len]; - auto data = new char[max_packet_len]; - memset(data, 0, max_packet_len); - memset(buf, 0, max_packet_len); - while (true) { - // auto size = generate_random_size(5, max_packet_len -40); - auto size = 10; - t1->send(data, size); - { - auto len = fcs.recv(t1, buf, buf_len); - if (len > 0) { - t1->recv(buf, len); - } - } - { - auto len = fcs.recv(t2, buf, buf_len); - if (len > 0) { - t2->recv(buf, len); - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + Len_Type buf_len = 10 * max_packet_len; + auto buf = new char[buf_len]; + auto data = new char[max_packet_len]; + memset(data, 0, max_packet_len); + memset(buf, 0, max_packet_len); + while (true) { + // auto size = generate_random_size(5, max_packet_len -40); + auto size = 10; + t1->send(data, size); + { + auto len = fcs.recv(t1, buf, buf_len); + if (len > 0) { + t1->recv(buf, len); + } } + { + auto len = fcs.recv(t2, buf, buf_len); + if (len > 0) { + t2->recv(buf, len); + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } } - // 接收测试 std::string create(Len_Type total_len) { #if ASSERT_SRP_Fixed_CB - ASSERT_GE(total_len, sizeof(Default_Serial_Packet_Header)); + ASSERT_GE(total_len, sizeof(Default_Serial_Packet_Header)); #endif - std::string buf(total_len, 30); - auto h = (Default_Serial_Packet_Header*)buf.c_str(); - h->header = default_serial_packet_header; - h->len = total_len; - h->crc = xcrc32((void*)(buf.c_str() + 8), total_len - 8); - return buf; + std::string buf(total_len, 30); + auto h = (Default_Serial_Packet_Header *)buf.c_str(); + h->header = default_serial_packet_header; + h->len = total_len; + h->crc = xcrc32((void *)(buf.c_str() + 8), total_len - 8); + return buf; } - void test_SRP_Fixed_CB(Get_Millisecond get_millisecond) { { Len_Type max_packet_len = 60; SRP_Fixed_CB *cb = create_default_SRP_Fixed_CB(max_packet_len); Len_Type all_len = 500; - std::vector data = create_order_vec(all_len, sizeof(Default_Serial_Packet_Header), max_packet_len); - std::vector spilt = create_order_vec(all_len, 1, max_packet_len * 2); - printf("data = {"); - for (size_t i = 0; i < data.size(); ++i) { - printf("%d,", data[i]); - } - printf("};\n"); - // 打印 spilt 向量 - printf("spilt = {"); - for (size_t i = 0; i < spilt.size(); ++i) { - printf("%d, ", spilt[i]); - } - printf("};\n"); - std::string d; - size_t cur = 0; - for (auto l : data) { - d += create(l); - } - cb->next_recv = [&data, &cur](Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { - auto d = data[cur]; - if (d != len) { - printf(" want[%d] but[%d] %llu\r\n", d, len, cur); - } - // ASSERT_EQ(d, len); - cur++; - }; - auto buf = const_cast(d.c_str()); - int offset = 0; - for (auto l : spilt) { - // cb->recv(buf + offset, l - 1, nullptr); - cb->recv(buf + offset, l, nullptr); - offset += l; - } + std::vector data = create_order_vec( + all_len, sizeof(Default_Serial_Packet_Header), max_packet_len); + std::vector spilt = + create_order_vec(all_len, 1, max_packet_len * 2); + printf("data = {"); + for (size_t i = 0; i < data.size(); ++i) { + printf("%d,", data[i]); } + printf("};\n"); + // 打印 spilt 向量 + printf("spilt = {"); + for (size_t i = 0; i < spilt.size(); ++i) { + printf("%d, ", spilt[i]); + } + printf("};\n"); + std::string d; + size_t cur = 0; + for (auto l : data) { + d += create(l); + } + cb->next_recv = [&data, &cur](Base_CB *bcb, Buf_Type buf, Len_Type len, + void *user) { + auto d = data[cur]; + if (d != len) { + printf(" want[%d] but[%d] %llu\r\n", d, len, cur); + } + // ASSERT_EQ(d, len); + cur++; + }; + auto buf = const_cast(d.c_str()); + int offset = 0; + for (auto l : spilt) { + // cb->recv(buf + offset, l - 1, nullptr); + cb->recv(buf + offset, l, nullptr); + offset += l; + } + } } - const IUINT32 default_serial_packet_header = 0x7C7C7C7C; - - -void SRP_Fixed_CB::send(Buf_Type buf, Len_Type len, void* user) { +void SRP_Fixed_CB::send(Buf_Type buf, Len_Type len, void *user) { #if ASSERT_SRP_Fixed_CB - PSC_ASSERT(add_pack); + PSC_ASSERT(add_pack); #endif - add_pack(this, buf, len, user); + add_pack(this, buf, len, user); } void SRP_Fixed_CB::recv(Buf_Type rcv_buf, Len_Type rcv_len, void *user) { - unpacker.push_data(rcv_buf, rcv_len, user); + unpacker.push_data(rcv_buf, rcv_len, user); } SRP_Fixed_CB::SRP_Fixed_CB(Len_Type total_len) : unpacker(total_len) { - unpacker.set_recv_callback([this](Buf_Type buf, Len_Type len, void *user) { - next_recv(this, buf, len, user); - }); + unpacker.set_recv_callback([this](Buf_Type buf, Len_Type len, void *user) { + next_recv(this, buf, len, user); + }); } -SRP_Fixed_CB* create_default_SRP_Fixed_CB(Len_Type total_len) { - auto ret = new SRP_Fixed_CB(total_len); - ret->unpacker.set_header_external((Buf_Type)&default_serial_packet_header, 4); - ret->unpacker.set_check([ret](Buf_Type buf, Len_Type len, Len_Type cur_skip_bytes) -> bool { - //std::cout << "check_crc_cur_skip_bytes:" << cur_skip_bytes << std::endl; +SRP_Fixed_CB *create_default_SRP_Fixed_CB(Len_Type total_len) { + auto ret = new SRP_Fixed_CB(total_len); + ret->unpacker.set_header_external((Buf_Type)&default_serial_packet_header, 4); + ret->unpacker.set_check( + [ret](Buf_Type buf, Len_Type len, Len_Type cur_skip_bytes) -> bool { + // std::cout << "check_crc_cur_skip_bytes:" << cur_skip_bytes << + // std::endl; auto h = reinterpret_cast(buf); - uint32_t new_crc = xcrc32(buf + ret->unpacker.length_offset(), len - ret->unpacker.length_offset()); + uint32_t new_crc = xcrc32(buf + ret->unpacker.length_offset(), + len - ret->unpacker.length_offset()); return h->crc == new_crc; - }); - ret->unpacker.set_length(offsetof(Default_Serial_Packet_Header, len), sizeof(Default_Serial_Packet_Header::len)); - ret->add_pack = [](SRP_Fixed_CB* bcb, Buf_Type data_buf, Len_Type data_len, void* user) { - Len_Type hdr_len = sizeof(Default_Serial_Packet_Header); - Len_Type total_len = data_len + hdr_len; - auto buf = static_cast(g_malloc(total_len)); - auto h = reinterpret_cast(buf); - memcpy(buf + hdr_len, data_buf, data_len); - h->header = default_serial_packet_header; - h->len = total_len; - h->crc = xcrc32((void*)(buf + 8), total_len - 8); - bcb->next_send(bcb, buf, total_len, user); + }); + ret->unpacker.set_length(offsetof(Default_Serial_Packet_Header, len), + sizeof(Default_Serial_Packet_Header::len)); + ret->add_pack = [](SRP_Fixed_CB *bcb, Buf_Type data_buf, Len_Type data_len, + void *user) { + Len_Type hdr_len = sizeof(Default_Serial_Packet_Header); + Len_Type total_len = data_len + hdr_len; + auto buf = static_cast(g_malloc(total_len)); + auto h = reinterpret_cast(buf); + memcpy(buf + hdr_len, data_buf, data_len); + h->header = default_serial_packet_header; + h->len = total_len; + h->crc = xcrc32((void *)(buf + 8), total_len - 8); + bcb->next_send(bcb, buf, total_len, user); #if Debug_SRP_Fixed_CB - std::cout << "add_pack_send:" << Psc::::mem2hex(std::string(buf, total_len)) << std::endl; + std::cout << "add_pack_send:" + << Psc:: ::mem2hex(std::string(buf, total_len)) << std::endl; #endif - g_free(buf); - }; - ret->next_send = [](Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { + g_free(buf); + }; + ret->next_send = [](Base_CB *bcb, Buf_Type buf, Len_Type len, void *user) { #if Debug_SRP_Fixed_CB - std::cout << "next_send:" << Psc::::mem2hex(std::string((const char*)buf, len)) << std::endl; + std::cout << "next_send:" + << Psc:: ::mem2hex(std::string((const char *)buf, len)) + << std::endl; #endif - }; - ret->next_recv = [](Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { + }; + ret->next_recv = [](Base_CB *bcb, Buf_Type buf, Len_Type len, void *user) { #if Debug_SRP_Fixed_CB - std::cout << "next_recv:" << Psc::::mem2hex(std::string((const char*)buf, len)) << std::endl; + std::cout << "next_recv:" + << Psc:: ::mem2hex(std::string((const char *)buf, len)) + << std::endl; #endif - }; - return ret; -} - - - + }; + return ret; } +} // namespace Psc #ifdef _USE_GTEST using namespace Psc; #include class SRP_Fixed_CB_Test : public ::testing::Test { public: - SRP_Fixed_CB *s1{}; - SRP_Fixed_CB *s2{}; + SRP_Fixed_CB *s1{}; + SRP_Fixed_CB *s2{}; - Flow_Channel_Simulator* fcs{}; - char* buffer{}; - char* data{}; - Len_Type buf_len{}; - Get_Millisecond get_millisecond = []() { - auto now = std::chrono::steady_clock::now(); - auto millis = std::chrono::duration_cast(now.time_since_epoch()).count(); - return static_cast(millis); - }; - const Len_Type max_packet_len = 50; + Flow_Channel_Simulator *fcs{}; + char *buffer{}; + char *data{}; + Len_Type buf_len{}; + Get_Millisecond get_millisecond = []() { + auto now = std::chrono::steady_clock::now(); + auto millis = std::chrono::duration_cast( + now.time_since_epoch()) + .count(); + return static_cast(millis); + }; + const Len_Type max_packet_len = 50; - Len_Type s1_recv_num = 0; - Len_Type s2_recv_num = 0; - void SetUp() override { - s1 = create_default_SRP_Fixed_CB(max_packet_len); - s2 = create_default_SRP_Fixed_CB(max_packet_len); - fcs = new Flow_Channel_Simulator(s1, s2, 0.00); - s1->next_send = [this](Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { - fcs->send(s1, buf, len); - }; - s2->next_recv = [this](Base_CB* bcb, Buf_Type buf, Len_Type len, void* user) { - s2_recv_num++; - }; + Len_Type s1_recv_num = 0; + Len_Type s2_recv_num = 0; + void SetUp() override { + s1 = create_default_SRP_Fixed_CB(max_packet_len); + s2 = create_default_SRP_Fixed_CB(max_packet_len); + fcs = new Flow_Channel_Simulator(s1, s2, 0.00); + s1->next_send = [this](Base_CB *bcb, Buf_Type buf, Len_Type len, + void *user) { fcs->send(s1, buf, len); }; + s2->next_recv = [this](Base_CB *bcb, Buf_Type buf, Len_Type len, + void *user) { s2_recv_num++; }; + // fcs->send(tr, buf, len); + // + // + // fcs->send(tr, buf, len); - // fcs->send(tr, buf, len); - // - // - // fcs->send(tr, buf, len); - - buf_len = 10 * max_packet_len; - buffer = new char[buf_len]; - data = new char[max_packet_len]; - memset(data, 0, max_packet_len); - memset(buffer, 0, max_packet_len); - } - void TearDown() override { - - - } + buf_len = 10 * max_packet_len; + buffer = new char[buf_len]; + data = new char[max_packet_len]; + memset(data, 0, max_packet_len); + memset(buffer, 0, max_packet_len); + } + void TearDown() override {} }; // 测试在通道无错误的情况下,任意位置断开可以解析出所有的包 -TEST_F(SRP_Fixed_CB_Test, Test_No_Error_Prase_all_packet_ok2) -{ - for (int i = 0; i < 100; ++i){ - auto size = generate_random_size(5, max_packet_len -40); - s1->send(data, size, nullptr); - { - auto len = fcs->recv(s1, buffer, buf_len); - while (len > 0) { - s1->recv(buffer, len, nullptr); - len = fcs->recv(s1, buffer, buf_len); - } - } - { - auto len = fcs->recv(s2, buffer, buf_len); - while (len > 0) { - s2->recv(buffer, len, nullptr); - len = fcs->recv(s2, buffer, buf_len); - } - } +TEST_F(SRP_Fixed_CB_Test, Test_No_Error_Prase_all_packet_ok2) { + for (int i = 0; i < 100; ++i) { + auto size = generate_random_size(5, max_packet_len - 40); + s1->send(data, size, nullptr); + { + auto len = fcs->recv(s1, buffer, buf_len); + while (len > 0) { + s1->recv(buffer, len, nullptr); + len = fcs->recv(s1, buffer, buf_len); + } } - ASSERT_EQ(fcs->get_buffer_size(s1), 0); - ASSERT_EQ(fcs->get_buffer_size(s2), 0); - ASSERT_EQ(s2_recv_num, 100); + { + auto len = fcs->recv(s2, buffer, buf_len); + while (len > 0) { + s2->recv(buffer, len, nullptr); + len = fcs->recv(s2, buffer, buf_len); + } + } + } + ASSERT_EQ(fcs->get_buffer_size(s1), 0); + ASSERT_EQ(fcs->get_buffer_size(s2), 0); + ASSERT_EQ(s2_recv_num, 100); } - - - class SRP_Fixed_CB_Test_With_Tree : public ::testing::Test { public: - SRP_Fixed_CB *s1{}; - SRP_Fixed_CB *s2{}; - Single_Test_Block t1{}; - Single_Test_Block t2{}; - Flow_Channel_Simulator* fcs{}; - char* buffer{}; - char* data{}; - Len_Type buf_len{}; - Get_Millisecond get_millisecond = []() { - auto now = std::chrono::steady_clock::now(); - auto millis = std::chrono::duration_cast(now.time_since_epoch()).count(); - return static_cast(millis); - }; - const Len_Type max_packet_len = 50; - void SetUp() override { - s1 = create_default_SRP_Fixed_CB(max_packet_len); - s2 = create_default_SRP_Fixed_CB(max_packet_len); - t1 = create_single_test(s1, get_millisecond); - t2 = create_single_test(s2, get_millisecond); + SRP_Fixed_CB *s1{}; + SRP_Fixed_CB *s2{}; + Single_Test_Block t1{}; + Single_Test_Block t2{}; + Flow_Channel_Simulator *fcs{}; + char *buffer{}; + char *data{}; + Len_Type buf_len{}; + Get_Millisecond get_millisecond = []() { + auto now = std::chrono::steady_clock::now(); + auto millis = std::chrono::duration_cast( + now.time_since_epoch()) + .count(); + return static_cast(millis); + }; + const Len_Type max_packet_len = 50; + void SetUp() override { + s1 = create_default_SRP_Fixed_CB(max_packet_len); + s2 = create_default_SRP_Fixed_CB(max_packet_len); + t1 = create_single_test(s1, get_millisecond); + t2 = create_single_test(s2, get_millisecond); #if !Test_CB_Print - t1.ttc->print = false; - t2.ttc->print = false; + t1.ttc->print = false; + t2.ttc->print = false; #endif - fcs = new Flow_Channel_Simulator(t1.tree, t2.tree, 0.00); - t1.tree->pack_send = [this](Proto_Tree* tr, Buf_Type buf, Len_Type len, void* user) { - fcs->send(tr, buf, len); - }; - t2.tree->pack_send = [this](Proto_Tree* tr, Buf_Type buf, Len_Type len, void* user) { - fcs->send(tr, buf, len); - }; - buf_len = 10 * max_packet_len; - buffer = new char[buf_len]; - data = new char[max_packet_len]; - memset(data, 0, max_packet_len); - memset(buffer, 0, max_packet_len); - } - void TearDown() override { - - - } + fcs = new Flow_Channel_Simulator(t1.tree, t2.tree, 0.00); + t1.tree->pack_send = [this](Proto_Tree *tr, Buf_Type buf, Len_Type len, + void *user) { fcs->send(tr, buf, len); }; + t2.tree->pack_send = [this](Proto_Tree *tr, Buf_Type buf, Len_Type len, + void *user) { fcs->send(tr, buf, len); }; + buf_len = 10 * max_packet_len; + buffer = new char[buf_len]; + data = new char[max_packet_len]; + memset(data, 0, max_packet_len); + memset(buffer, 0, max_packet_len); + } + void TearDown() override {} }; - // 测试在通道无错误的情况下,任意位置断开可以解析出所有的包 -TEST_F(SRP_Fixed_CB_Test_With_Tree, Test_No_Error_Prase_all_packet_ok) -{ - for (int i = 0; i < 100; ++i){ - auto size = generate_random_size(5, max_packet_len -40); - t1.tree->send(data, size); - { - auto len = fcs->recv(t1.tree, buffer, buf_len); - while (len > 0) { - t1.tree->recv(buffer, len); - len = fcs->recv(t1.tree, buffer, buf_len); - } - } - { - auto len = fcs->recv(t2.tree, buffer, buf_len); - while (len > 0) { - t2.tree->recv(buffer, len); - len = fcs->recv(t2.tree, buffer, buf_len); - } - } +TEST_F(SRP_Fixed_CB_Test_With_Tree, Test_No_Error_Prase_all_packet_ok) { + for (int i = 0; i < 100; ++i) { + auto size = generate_random_size(5, max_packet_len - 40); + t1.tree->send(data, size); + { + auto len = fcs->recv(t1.tree, buffer, buf_len); + while (len > 0) { + t1.tree->recv(buffer, len); + len = fcs->recv(t1.tree, buffer, buf_len); + } } + { + auto len = fcs->recv(t2.tree, buffer, buf_len); + while (len > 0) { + t2.tree->recv(buffer, len); + len = fcs->recv(t2.tree, buffer, buf_len); + } + } + } - PSC_ASSERT(t1.ttc->r_ctx.len_error_num == 0, ""); - PSC_ASSERT(t2.ttc->r_ctx.len_error_num == 0, ""); - PSC_ASSERT(t1.ttc->r_ctx.crc_error_num == 0, ""); - PSC_ASSERT(t2.ttc->r_ctx.crc_error_num == 0, ""); - PSC_ASSERT_EQ(fcs->get_buffer_size(t1.tree), 0); - PSC_ASSERT_EQ(fcs->get_buffer_size(t2.tree), 0); + PSC_ASSERT(t1.ttc->r_ctx.len_error_num == 0, ""); + PSC_ASSERT(t2.ttc->r_ctx.len_error_num == 0, ""); + PSC_ASSERT(t1.ttc->r_ctx.crc_error_num == 0, ""); + PSC_ASSERT(t2.ttc->r_ctx.crc_error_num == 0, ""); + PSC_ASSERT_EQ(fcs->get_buffer_size(t1.tree), 0); + PSC_ASSERT_EQ(fcs->get_buffer_size(t2.tree), 0); } - #endif \ No newline at end of file diff --git a/Core/transmit_protocol/other_node/SRP_Fixed_CB.h b/Core/transmit_protocol/other_node/SRP_Fixed_CB.h index 4870454..40ad70e 100644 --- a/Core/transmit_protocol/other_node/SRP_Fixed_CB.h +++ b/Core/transmit_protocol/other_node/SRP_Fixed_CB.h @@ -3,24 +3,25 @@ #include "Universal_Unpacker.h" namespace Psc { - struct SRP_Fixed_CB : Base_CB { - void send(Buf_Type buf, Len_Type len, void* user) override; - void recv(Buf_Type rcv_buf, Len_Type rcv_len, void* user) override; - Normal_Universal_Unpacker unpacker; - explicit SRP_Fixed_CB(Len_Type total_len); - std::function add_pack{}; - }; +struct SRP_Fixed_CB : Base_CB { + void send(Buf_Type buf, Len_Type len, void *user) override; + void recv(Buf_Type rcv_buf, Len_Type rcv_len, void *user) override; + Normal_Universal_Unpacker unpacker; + explicit SRP_Fixed_CB(Len_Type total_len); + std::function + add_pack{}; +}; - // 测试代码 - extern const IUINT32 default_serial_packet_header; - struct Default_Serial_Packet_Header { - using CRC_Type = uint32_t; - IUINT32 header = default_serial_packet_header; - CRC_Type crc{}; - Len_Type len{}; - }; - SRP_Fixed_CB* create_default_SRP_Fixed_CB(Len_Type total_len); - void test_SRP_Fixed_CB(Get_Millisecond get_millisecond); - void test_SRP_Fixed_CB_While(Get_Millisecond get_millisecond); +// 测试代码 +extern const IUINT32 default_serial_packet_header; +struct Default_Serial_Packet_Header { + using CRC_Type = uint32_t; + IUINT32 header = default_serial_packet_header; + CRC_Type crc{}; + Len_Type len{}; +}; +SRP_Fixed_CB *create_default_SRP_Fixed_CB(Len_Type total_len); +void test_SRP_Fixed_CB(Get_Millisecond get_millisecond); +void test_SRP_Fixed_CB_While(Get_Millisecond get_millisecond); -} +} // namespace Psc diff --git a/Core/transmit_protocol/other_node/Transmission_Test.cpp b/Core/transmit_protocol/other_node/Transmission_Test.cpp index 8d5f66f..2eb6fd2 100644 --- a/Core/transmit_protocol/other_node/Transmission_Test.cpp +++ b/Core/transmit_protocol/other_node/Transmission_Test.cpp @@ -3,196 +3,203 @@ namespace Psc { typedef struct { - Transmission_Test_CB* cb; - void* user; + Transmission_Test_CB *cb; + void *user; } TTT; // 实际数据的出口 -void tt_send(Base_CB* bcb, Buf_Type buf, Len_Type len, void* user){ - TTT* ttt = (TTT*)user; - Transmission_Test_CB* cb = ttt->cb; - Send_Context* ctx = &cb->s_ctx; - ctx->send_total++; - ctx->send_seq++; - //update_value(&ctx->pack_bytes, cb->get_millisecond(), len); +void tt_send(Base_CB *bcb, Buf_Type buf, Len_Type len, void *user) { + TTT *ttt = (TTT *)user; + Transmission_Test_CB *cb = ttt->cb; + Send_Context *ctx = &cb->s_ctx; + ctx->send_total++; + ctx->send_seq++; + // update_value(&ctx->pack_bytes, cb->get_millisecond(), len); - cb->next_send((Base_CB*)cb, buf, len, ttt->user); + cb->next_send((Base_CB *)cb, buf, len, ttt->user); - if (cb->show_send_statistics_info) { - float avt = ctx->true_bytes.average_speed; - float avp = ctx->pack_bytes.average_speed; - float ivt = ctx->true_bytes.instant_speed; - float ivp = ctx->pack_bytes.instant_speed; - if (cb->print) { - printf("【 发送统计信息 seq:[%u] total:[%u] 】\r\n",ctx->send_seq, ctx->send_total); - printf("\t【 平均(KB/s): %f/%f %f %% \r\n", avt, avp, 100.0f * avt/avp); - printf("\t【 瞬时(KB/s): %f/%f %f %% \r\n", ivt, ivp, 100.0f * ivt/ivp); - } + if (cb->show_send_statistics_info) { + float avt = ctx->true_bytes.average_speed; + float avp = ctx->pack_bytes.average_speed; + float ivt = ctx->true_bytes.instant_speed; + float ivp = ctx->pack_bytes.instant_speed; + if (cb->print) { + printf("【 发送统计信息 seq:[%u] total:[%u] 】\r\n", ctx->send_seq, + ctx->send_total); + printf("\t【 平均(KB/s): %f/%f %f %% \r\n", avt, avp, + 100.0f * avt / avp); + printf("\t【 瞬时(KB/s): %f/%f %f %% \r\n", ivt, ivp, + 100.0f * ivt / ivp); } + } } +void tt_recv(Base_CB *bcb, Buf_Type buf, Len_Type len, void *user) { + TTT *ttt = (TTT *)user; + Transmission_Test_CB *cb = ttt->cb; + void *recv_user = ttt->user; + auto pkt = reinterpret_cast(buf); + Recv_Context *ctx = &cb->r_ctx; + if (pkt->length != len) { + ctx->len_error_num++; + return; + } + IUINT32 old_crc = pkt->crc; + pkt->crc = 0; + IUINT32 cacl_crc = xcrc32(pkt, pkt->length); + if (cacl_crc != old_crc) { + ctx->crc_error_num++; + return; + } + IUINT32 current = cb->get_millisecond(); + IUINT32 delay = current - pkt->ts; + ctx->count++; + ctx->current = current; + ctx->delay.update(delay); -void tt_recv(Base_CB* bcb, Buf_Type buf, Len_Type len, void* user){ - TTT* ttt = (TTT*)user; - Transmission_Test_CB* cb = ttt->cb; - void* recv_user = ttt->user; + IUINT32 expected = ctx->next; + IUINT32 lose_num = pkt->sn - ctx->next; + if (pkt->sn != expected) { + ctx->seq_error_num += lose_num; + ctx->next = pkt->sn; + } + ctx->next++; + // update_value(&ctx->true_bytes, cb->get_millisecond(), pkt->length); - auto pkt = reinterpret_cast(buf); - Recv_Context* ctx = &cb->r_ctx; - if (pkt->length != len) { - ctx->len_error_num++; - return; - } - IUINT32 old_crc = pkt->crc; - pkt->crc = 0; - IUINT32 cacl_crc = xcrc32(pkt, pkt->length); - if (cacl_crc != old_crc) { - ctx->crc_error_num++; - return; - } - IUINT32 current = cb->get_millisecond(); - IUINT32 delay = current - pkt->ts; - ctx->count++; - ctx->current = current; - - ctx->delay.update(delay); - - IUINT32 expected = ctx->next; - IUINT32 lose_num = pkt->sn - ctx->next; - if (pkt->sn != expected) { - ctx->seq_error_num += lose_num; - ctx->next = pkt->sn; - } - ctx->next++; - //update_value(&ctx->true_bytes, cb->get_millisecond(), pkt->length); - - cb->next_recv((Base_CB*)cb, buf, len, recv_user); - auto sum = (double)pkt->sn; - double len_rate = (double)ctx->len_error_num / sum * 100.0; - double error_crc_rate = (double)ctx->crc_error_num / sum * 100.0; - double lose_rate = (double)ctx->seq_error_num / sum * 100.0; - - - if (cb->show_recv_statistics_info) { - float avt = ctx->true_bytes.average_speed; - float avp = ctx->pack_bytes.average_speed; - float ivt = ctx->true_bytes.instant_speed; - float ivp = ctx->pack_bytes.instant_speed; - if (cb->print) { - printf("【 接收统计信息 seq:[%u] ts:[%u] current:[%u] len:[%u] except:[%u] lose:[%u] 】\r\n", pkt->sn, pkt->ts, current, pkt->length, expected, lose_num); - printf("\t【 延迟: instant:%f average:%f range[%f,%f]ms \r\n", ctx->delay.instant, ctx->delay.average, ctx->delay.min, ctx->delay.max); - printf("\t【 长度错误:[%u] [%f %%] \r\n", ctx->len_error_num, len_rate); - printf("\t【 校验错误:[%u] [%f %%] \r\n", ctx->crc_error_num, error_crc_rate); - printf("\t【 丢包率:[%u] [%f %%] \r\n", ctx->seq_error_num, lose_rate); - printf("\t【 平均(KB/s): %f/%f %f %% \r\n", avt, avp, 100.0f * avt/avp); - printf("\t【 瞬时(KB/s): %f/%f %f %% \r\n", ivt, ivp, 100.0f * ivt/ivp); - printf("\r\n"); - } - Proto_Tree* tr = cb->pn->tn->tr; - tr->print_state_info(); + cb->next_recv((Base_CB *)cb, buf, len, recv_user); + auto sum = (double)pkt->sn; + double len_rate = (double)ctx->len_error_num / sum * 100.0; + double error_crc_rate = (double)ctx->crc_error_num / sum * 100.0; + double lose_rate = (double)ctx->seq_error_num / sum * 100.0; + + if (cb->show_recv_statistics_info) { + float avt = ctx->true_bytes.average_speed; + float avp = ctx->pack_bytes.average_speed; + float ivt = ctx->true_bytes.instant_speed; + float ivp = ctx->pack_bytes.instant_speed; + if (cb->print) { + printf("【 接收统计信息 seq:[%u] ts:[%u] current:[%u] len:[%u] " + "except:[%u] lose:[%u] 】\r\n", + pkt->sn, pkt->ts, current, pkt->length, expected, lose_num); + printf("\t【 延迟: instant:%f average:%f range[%f,%f]ms \r\n", + ctx->delay.instant, ctx->delay.average, ctx->delay.min, + ctx->delay.max); + printf("\t【 长度错误:[%u] [%f %%] \r\n", ctx->len_error_num, len_rate); + printf("\t【 校验错误:[%u] [%f %%] \r\n", ctx->crc_error_num, + error_crc_rate); + printf("\t【 丢包率:[%u] [%f %%] \r\n", ctx->seq_error_num, lose_rate); + printf("\t【 平均(KB/s): %f/%f %f %% \r\n", avt, avp, + 100.0f * avt / avp); + printf("\t【 瞬时(KB/s): %f/%f %f %% \r\n", ivt, ivp, + 100.0f * ivt / ivp); + printf("\r\n"); } + Proto_Tree *tr = cb->pn->tn->tr; + tr->print_state_info(); + } } - -void Transmission_Test_Pack_Send (Proto_Tree_Node* n, Buf_Type buf, Len_Type len) { - auto cb = static_cast(n->cb); - Send_Context* ctx = &cb->s_ctx; - ctx->pack_bytes.update(len); +void Transmission_Test_Pack_Send(Proto_Tree_Node *n, Buf_Type buf, + Len_Type len) { + auto cb = static_cast(n->cb); + Send_Context *ctx = &cb->s_ctx; + ctx->pack_bytes.update(len); } -void Transmission_Test_Pack_Recv (Proto_Tree_Node* n, Buf_Type buf, Len_Type len) { - auto cb = static_cast(n->cb); - Recv_Context* ctx = &cb->r_ctx; - ctx->pack_bytes.update(len); +void Transmission_Test_Pack_Recv(Proto_Tree_Node *n, Buf_Type buf, + Len_Type len) { + auto cb = static_cast(n->cb); + Recv_Context *ctx = &cb->r_ctx; + ctx->pack_bytes.update(len); } -void Transmission_Test_True_Send (Proto_Tree_Node* n, Buf_Type buf, Len_Type len) { - auto cb = static_cast(n->cb); - Send_Context* ctx = &cb->s_ctx; - ctx->true_bytes.update(len); +void Transmission_Test_True_Send(Proto_Tree_Node *n, Buf_Type buf, + Len_Type len) { + auto cb = static_cast(n->cb); + Send_Context *ctx = &cb->s_ctx; + ctx->true_bytes.update(len); } -void Transmission_Test_True_Recv (Proto_Tree_Node* n, Buf_Type buf, Len_Type len) { - auto cb = static_cast(n->cb); - Recv_Context* ctx = &cb->r_ctx; - ctx->true_bytes.update(len); +void Transmission_Test_True_Recv(Proto_Tree_Node *n, Buf_Type buf, + Len_Type len) { + auto cb = static_cast(n->cb); + Recv_Context *ctx = &cb->r_ctx; + ctx->true_bytes.update(len); } - Transmission_Test_CB::Transmission_Test_CB(Get_Millisecond get_millisecond) { - this->get_millisecond = get_millisecond; - show_send_statistics_info = false; - show_recv_statistics_info = true; - IUINT32 current = get_millisecond(); - { - Send_Context* ctx = &s_ctx; - ctx->send_seq = 0; - ctx->send_total = 0; - ctx->packet_seq = 0; - } - { - Recv_Context* ctx = &r_ctx; - ctx->count = 0; - ctx->next = 0; - ctx->total = 0; - ctx->crc_error_num = 0; - ctx->len_error_num = 0; - ctx->seq_error_num = 0; - } - { - cb = new UDP_Serial(4000, 0x75757575, true); - UDP_Serial* scb = cb; - scb->use_crc = false; - scb->next_send = tt_send; - scb->next_recv = tt_recv; - } - test_order = true; + this->get_millisecond = get_millisecond; + show_send_statistics_info = false; + show_recv_statistics_info = true; + IUINT32 current = get_millisecond(); + { + Send_Context *ctx = &s_ctx; + ctx->send_seq = 0; + ctx->send_total = 0; + ctx->packet_seq = 0; + } + { + Recv_Context *ctx = &r_ctx; + ctx->count = 0; + ctx->next = 0; + ctx->total = 0; + ctx->crc_error_num = 0; + ctx->len_error_num = 0; + ctx->seq_error_num = 0; + } + { + cb = new UDP_Serial(4000, 0x75757575, true); + UDP_Serial *scb = cb; + scb->use_crc = false; + scb->next_send = tt_send; + scb->next_recv = tt_recv; + } + test_order = true; } - Transmission_Test_CB::~Transmission_Test_CB() { delete cb; } -void Transmission_Test_CB::send(Buf_Type buf, Len_Type data_len, void* user) { - UDP_Serial* scb = cb; - TTT ttt; - ttt.cb = this; - ttt.user = user; - Send_Context* s = &s_ctx; - static IUINT32 packet_len = sizeof(Transmission_Test_Packet_Header); - IUINT32 len = packet_len + data_len; - auto pkt = static_cast(g_malloc(len)); - pkt->length = len; - pkt->ts = get_millisecond(); - pkt->sn = s->packet_seq; - s->packet_seq++; - memmove((char*)pkt + packet_len, buf, data_len); - pkt->crc = 0; - pkt->crc = xcrc32(pkt, len); - cb->send((Buf_Type)pkt, len, &ttt); +void Transmission_Test_CB::send(Buf_Type buf, Len_Type data_len, void *user) { + UDP_Serial *scb = cb; + TTT ttt; + ttt.cb = this; + ttt.user = user; + Send_Context *s = &s_ctx; + static IUINT32 packet_len = sizeof(Transmission_Test_Packet_Header); + IUINT32 len = packet_len + data_len; + auto pkt = static_cast(g_malloc(len)); + pkt->length = len; + pkt->ts = get_millisecond(); + pkt->sn = s->packet_seq; + s->packet_seq++; + memmove((char *)pkt + packet_len, buf, data_len); + pkt->crc = 0; + pkt->crc = xcrc32(pkt, len); + cb->send((Buf_Type)pkt, len, &ttt); } -void Transmission_Test_CB::recv(Buf_Type buf, Len_Type len, void* user) { - UDP_Serial* scb = cb; - TTT ttt; - ttt.cb = this; - ttt.user = user; - cb->recv((Buf_Type)buf, len, &ttt); - Recv_Context* ctx = &r_ctx; +void Transmission_Test_CB::recv(Buf_Type buf, Len_Type len, void *user) { + UDP_Serial *scb = cb; + TTT ttt; + ttt.cb = this; + ttt.user = user; + cb->recv((Buf_Type)buf, len, &ttt); + Recv_Context *ctx = &r_ctx; } void Transmission_Test_CB::final_init() { - pn->tn->true_send = Transmission_Test_True_Send; - pn->tn->true_recv = Transmission_Test_True_Recv; - pn->tn->pack_recv = Transmission_Test_Pack_Recv; - pn->tn->pack_send = Transmission_Test_Pack_Send; + pn->tn->true_send = Transmission_Test_True_Send; + pn->tn->true_recv = Transmission_Test_True_Recv; + pn->tn->pack_recv = Transmission_Test_Pack_Recv; + pn->tn->pack_send = Transmission_Test_Pack_Send; } - -Single_Test_Block create_single_test(Base_CB* cb, Get_Millisecond get_millisecond) { - auto tr = new Proto_Tree(); - auto ttc = new Transmission_Test_CB(get_millisecond); - auto par = tr->append(nullptr, ttc); - tr->append(par, cb); - tr->create(); - return {tr, ttc}; +Single_Test_Block create_single_test(Base_CB *cb, + Get_Millisecond get_millisecond) { + auto tr = new Proto_Tree(); + auto ttc = new Transmission_Test_CB(get_millisecond); + auto par = tr->append(nullptr, ttc); + tr->append(par, cb); + tr->create(); + return {tr, ttc}; } } \ No newline at end of file diff --git a/Core/transmit_protocol/other_node/Transmission_Test.h b/Core/transmit_protocol/other_node/Transmission_Test.h index 8002ab2..9d45d7e 100644 --- a/Core/transmit_protocol/other_node/Transmission_Test.h +++ b/Core/transmit_protocol/other_node/Transmission_Test.h @@ -1,67 +1,63 @@ #pragma once -#include "../global.h" #include "../../../Core/Statistics/Statistics.h" +#include "../global.h" #include "udp_serial.h" -namespace Psc{ +namespace Psc { typedef struct Transmission_Test_CB Transmission_Test_CB; - - - - typedef struct { - IUINT32 total; - Value_Statistics delay; - IUINT32 count; - IUINT32 next; - IUINT32 current; - IUINT32 crc_error_num; - IUINT32 len_error_num; - IUINT32 seq_error_num; - Speed_Statistics true_bytes; - Speed_Statistics pack_bytes; + IUINT32 total; + Value_Statistics delay; + IUINT32 count; + IUINT32 next; + IUINT32 current; + IUINT32 crc_error_num; + IUINT32 len_error_num; + IUINT32 seq_error_num; + Speed_Statistics true_bytes; + Speed_Statistics pack_bytes; } Recv_Context; typedef struct { - IUINT32 send_total; - IUINT32 send_seq; - IUINT32 packet_seq; - Speed_Statistics true_bytes; - Speed_Statistics pack_bytes; + IUINT32 send_total; + IUINT32 send_seq; + IUINT32 packet_seq; + Speed_Statistics true_bytes; + Speed_Statistics pack_bytes; } Send_Context; - struct Transmission_Test_CB : Base_CB { - UDP_Serial* cb; - Send_Context s_ctx{}; - Recv_Context r_ctx{}; - Get_Millisecond get_millisecond; - bool test_order; - bool show_send_statistics_info; - bool show_recv_statistics_info; - bool print = true; - explicit Transmission_Test_CB(Get_Millisecond get_millisecond); - ~Transmission_Test_CB() override; - void send(Buf_Type buf, Len_Type len, void* user) override; - void recv(Buf_Type buf, Len_Type len, void* user) override; - void final_init() override; + UDP_Serial *cb; + Send_Context s_ctx{}; + Recv_Context r_ctx{}; + Get_Millisecond get_millisecond; + bool test_order; + bool show_send_statistics_info; + bool show_recv_statistics_info; + bool print = true; + explicit Transmission_Test_CB(Get_Millisecond get_millisecond); + ~Transmission_Test_CB() override; + void send(Buf_Type buf, Len_Type len, void *user) override; + void recv(Buf_Type buf, Len_Type len, void *user) override; + void final_init() override; }; struct Single_Test_Block { - Proto_Tree* tree; - Transmission_Test_CB* ttc; + Proto_Tree *tree; + Transmission_Test_CB *ttc; }; -Single_Test_Block create_single_test(Base_CB* cb, Get_Millisecond get_millisecond); +Single_Test_Block create_single_test(Base_CB *cb, + Get_Millisecond get_millisecond); // 创建包 typedef struct { - IUINT32 length; - IUINT32 sn; - IUINT32 ts; - IUINT32 crc; + IUINT32 length; + IUINT32 sn; + IUINT32 ts; + IUINT32 crc; } Transmission_Test_Packet_Header; -} +} // namespace Psc diff --git a/Core/transmit_protocol/other_node/Universal_Unpacker_Impl.hpp b/Core/transmit_protocol/other_node/Universal_Unpacker_Impl.hpp index f04ad05..a253b9b 100644 --- a/Core/transmit_protocol/other_node/Universal_Unpacker_Impl.hpp +++ b/Core/transmit_protocol/other_node/Universal_Unpacker_Impl.hpp @@ -4,372 +4,422 @@ #include #include - #define Debug_SRP_Fixed_CB 0 #define ASSERT_SRP_Fixed_CB 0 #define Test_CB_Print 0 namespace Psc { #if Debug_SRP_Fixed_CB -void print_state(const char* prefix, SRP_Fixed_CB* cb) { - printf("【%s】: cache_packet_len:%d, cache_len: %d/%d state:【%s】 \r\n", prefix, cb->cache_packet_len, cb->cache_valid_len, cb->cache_total_len, - recv_state_to_string(cb->state)); +void print_state(const char *prefix, SRP_Fixed_CB *cb) { + printf("【%s】: cache_packet_len:%d, cache_len: %d/%d state:【%s】 \r\n", + prefix, cb->cache_packet_len, cb->cache_valid_len, cb->cache_total_len, + recv_state_to_string(cb->state)); } #endif inline bool mem_equal(Buf_Type buf1, Buf_Type buf2, size_t len) { - for (size_t i = 0; i < len; ++i) { - if (buf1[i] != buf2[i]) { - return false; // 一旦有不匹配的字节,就可以提前返回 - } + for (size_t i = 0; i < len; ++i) { + if (buf1[i] != buf2[i]) { + return false; // 一旦有不匹配的字节,就可以提前返回 } - return true; // 完全匹配 + } + return true; // 完全匹配 } -template -class Universal_Unpacker_Impl { +template class Universal_Unpacker_Impl { public: - enum Recv_State { - Empty, // 缓冲区没有有效数据 - Expect_Hdr, // 缓冲区有数据但是未读取到包头字段 内容前半部分必然符合包头结构 数据小于包头长度 - Expect_Len, // 缓冲区有数据但是未读取到长度字段 - Expect_All // 缓冲区有数据,读取到长度字段, 但是仍不完整,等待数据中 - }; - Recv_State state = Empty; - bool handle_whole_packet(Buf_Type rcv_buf, Len_Type rcv_len, void* user, bool no_copy); - void handle_new_recv_data(Buf_Type rcv_buf, Len_Type rcv_len, void* user, bool memmove); - Len_Type handle_with_old_buffer(Buf_Type rcv_buf, Len_Type rcv_len, void* user); - void append_buffer(Buf_Type buf, Len_Type len, bool move); - void push_data(Buf_Type rcv_buf, Len_Type rcv_len, void* user); - bool internal_header = false; - Buf_Type hdr_buf{}; - Len_Type hdr_len{}; - Buf_Type cache_buf{}; // 必要时缓存 - Len_Type cache_packet_len{}; // 当前包长度 - Len_Type cache_valid_len{}; // 有效数据长度 - Len_Type cache_total_len{}; // 缓冲区长度, 也是单包最大长度 - Len_Type len_offset{}; - Len_Type len_len{}; - Len_Type cur_skip_bytes = 0; // 距离上一包有效数据 跳过的数据数量 - typename Universal_Unpacker::Get_Len get_len{}; - typename Universal_Unpacker::Check check{}; - typename Universal_Unpacker::Len_Error_Call_Back len_error_call_back{}; - typename Universal_Unpacker::Check_Error_Call_Back check_error_call_back{}; - typename Universal_Unpacker::Recv_call_back recv_call_back{}; - explicit Universal_Unpacker_Impl(Len_Type total_len) : cache_total_len(total_len) { - cache_buf = new char[total_len]; - state = Universal_Unpacker_Impl::Empty; - } - ~Universal_Unpacker_Impl() { - delete[] cache_buf; - if (internal_header) { - delete[] hdr_buf; - } + enum Recv_State { + Empty, // 缓冲区没有有效数据 + Expect_Hdr, // 缓冲区有数据但是未读取到包头字段 内容前半部分必然符合包头结构 + // 数据小于包头长度 + Expect_Len, // 缓冲区有数据但是未读取到长度字段 + Expect_All // 缓冲区有数据,读取到长度字段, 但是仍不完整,等待数据中 + }; + Recv_State state = Empty; + bool handle_whole_packet(Buf_Type rcv_buf, Len_Type rcv_len, void *user, + bool no_copy); + void handle_new_recv_data(Buf_Type rcv_buf, Len_Type rcv_len, void *user, + bool memmove); + Len_Type handle_with_old_buffer(Buf_Type rcv_buf, Len_Type rcv_len, + void *user); + void append_buffer(Buf_Type buf, Len_Type len, bool move); + void push_data(Buf_Type rcv_buf, Len_Type rcv_len, void *user); + bool internal_header = false; + Buf_Type hdr_buf{}; + Len_Type hdr_len{}; + Buf_Type cache_buf{}; // 必要时缓存 + Len_Type cache_packet_len{}; // 当前包长度 + Len_Type cache_valid_len{}; // 有效数据长度 + Len_Type cache_total_len{}; // 缓冲区长度, 也是单包最大长度 + Len_Type len_offset{}; + Len_Type len_len{}; + Len_Type cur_skip_bytes = 0; // 距离上一包有效数据 跳过的数据数量 + typename Universal_Unpacker::Get_Len get_len{}; + typename Universal_Unpacker::Check check{}; + typename Universal_Unpacker::Len_Error_Call_Back + len_error_call_back{}; + typename Universal_Unpacker::Check_Error_Call_Back + check_error_call_back{}; + typename Universal_Unpacker::Recv_call_back + recv_call_back{}; + explicit Universal_Unpacker_Impl(Len_Type total_len) + : cache_total_len(total_len) { + cache_buf = new char[total_len]; + state = Universal_Unpacker_Impl::Empty; + } + ~Universal_Unpacker_Impl() { + delete[] cache_buf; + if (internal_header) { + delete[] hdr_buf; } + } }; template -void Universal_Unpacker_Impl::append_buffer(Buf_Type buf, Len_Type len, bool move) { +void Universal_Unpacker_Impl::append_buffer(Buf_Type buf, + Len_Type len, + bool move) { #if ASSERT_SRP_Fixed_CB - ASSERT_LE(cache_valid_len + len, cache_total_len); + ASSERT_LE(cache_valid_len + len, cache_total_len); #endif - if (!move) { - memcpy(cache_buf + cache_valid_len, buf, len); - } else { - memmove(cache_buf + cache_valid_len, buf, len); - } - cache_valid_len += len; + if (!move) { + memcpy(cache_buf + cache_valid_len, buf, len); + } else { + memmove(cache_buf + cache_valid_len, buf, len); + } + cache_valid_len += len; } // 返回吸收使用了多长的长度的数据来处理第一包 template -Len_Type Universal_Unpacker_Impl::handle_with_old_buffer(Buf_Type rcv_buf, Len_Type rcv_len, void* user) { +Len_Type Universal_Unpacker_Impl::handle_with_old_buffer( + Buf_Type rcv_buf, Len_Type rcv_len, void *user) { #if Debug_SRP_Fixed_CB - std::cout << "=============== handle_with_old_buffer 进入! =============== " << std::endl; - std::cout << "开始状态:" << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, cache_total_len) << std::endl; - std::cout << "cache_buf[" << cache_valid_len << "]:" << Psc::::mem2hex(std::string(cache_buf, cache_valid_len)) << std::endl; - std::cout << "rcv_buf[" << rcv_len << "]:" << Psc::::mem2hex(std::string(rcv_buf, rcv_len)) << std::endl; + std::cout << "=============== handle_with_old_buffer 进入! =============== " + << std::endl; + std::cout << "开始状态:" + << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, + cache_total_len) + << std::endl; + std::cout << "cache_buf[" << cache_valid_len + << "]:" << Psc:: ::mem2hex(std::string(cache_buf, cache_valid_len)) + << std::endl; + std::cout << "rcv_buf[" << rcv_len + << "]:" << Psc:: ::mem2hex(std::string(rcv_buf, rcv_len)) + << std::endl; #endif - retry: - Len_Type i = 0; // i必然是从0开始的 +retry: + Len_Type i = 0; // i必然是从0开始的 #if ASSERT_SRP_Fixed_CB - ASSERT_NE(state,Empty); - ASSERT_LE(cache_valid_len, cache_total_len); + ASSERT_NE(state, Empty); + ASSERT_LE(cache_valid_len, cache_total_len); #endif + auto advance = [&](Len_Type take) { + append_buffer(rcv_buf + i, take, false); + i += take; + }; - auto advance = [&](Len_Type take) { - append_buffer(rcv_buf + i, take, false); - i += take; - }; - - while (true) { - Buf_Type cur_buf = rcv_buf + i; - Len_Type remain_len = rcv_len - i; - if (state == Expect_Hdr) { + while (true) { + Buf_Type cur_buf = rcv_buf + i; + Len_Type remain_len = rcv_len - i; + if (state == Expect_Hdr) { #if ASSERT_SRP_Fixed_CB - ASSERT_EQ(mem_equal(cache_buf, hdr_buf, cache_valid_len), true); + ASSERT_EQ(mem_equal(cache_buf, hdr_buf, cache_valid_len), true); #endif - Len_Type min = hdr_len; - Len_Type need = min - cache_valid_len; - if (remain_len < need) { - advance(remain_len); - break; - } - advance(need); - if (mem_equal(cache_buf, hdr_buf, hdr_len)) { - state = Expect_Len; - } else { - state = Empty; - cache_valid_len = 0; - break; - } - } else if (state == Expect_Len) { - Len_Type min = len_offset + len_len; - Len_Type need = min - cache_valid_len; - if (remain_len < need) { - advance(remain_len); - break; - } - advance(need); + Len_Type min = hdr_len; + Len_Type need = min - cache_valid_len; + if (remain_len < need) { + advance(remain_len); + break; + } + advance(need); + if (mem_equal(cache_buf, hdr_buf, hdr_len)) { + state = Expect_Len; + } else { + state = Empty; + cache_valid_len = 0; + break; + } + } else if (state == Expect_Len) { + Len_Type min = len_offset + len_len; + Len_Type need = min - cache_valid_len; + if (remain_len < need) { + advance(remain_len); + break; + } + advance(need); - if (!get_len) { - cache_packet_len = *reinterpret_cast(cache_buf + len_offset); - } else { - cache_packet_len = get_len(cache_buf + len_offset); - } - if (cache_packet_len <= cache_total_len) { - state = Expect_All; - } else { - if (len_error_call_back) len_error_call_back(cache_buf, cache_valid_len); - // 错误的长度 TODO 长度 处理逻辑错误 缺乏出口 设计 + if (!get_len) { + cache_packet_len = + *reinterpret_cast(cache_buf + len_offset); + } else { + cache_packet_len = get_len(cache_buf + len_offset); + } + if (cache_packet_len <= cache_total_len) { + state = Expect_All; + } else { + if (len_error_call_back) + len_error_call_back(cache_buf, cache_valid_len); + // 错误的长度 TODO 长度 处理逻辑错误 缺乏出口 设计 #if Debug_SRP_Fixed_CB - std::cout << "【解析到错误的长度】" - << Psc::::mem2hex(std::string(cache_buf, cache_valid_len)) - << VAR_STR_2(cache_valid_len, cache_packet_len) - << std::endl; + std::cout << "【解析到错误的长度】" + << Psc:: ::mem2hex(std::string(cache_buf, cache_valid_len)) + << VAR_STR_2(cache_valid_len, cache_packet_len) << std::endl; #endif - state = Empty; - cache_valid_len = 0; - cache_packet_len = 0; - cur_skip_bytes = 0; - break; - } - } else if (state == Expect_All) { - Len_Type min = cache_packet_len; - Len_Type need = min - cache_valid_len; - if (remain_len < need) { - advance(remain_len); - break; - } - advance(need); - bool ok = handle_whole_packet(cache_buf, cache_packet_len, user, false); - if (!ok) { - Len_Type old_valid_len = cache_valid_len - i; + state = Empty; + cache_valid_len = 0; + cache_packet_len = 0; + cur_skip_bytes = 0; + break; + } + } else if (state == Expect_All) { + Len_Type min = cache_packet_len; + Len_Type need = min - cache_valid_len; + if (remain_len < need) { + advance(remain_len); + break; + } + advance(need); + bool ok = handle_whole_packet(cache_buf, cache_packet_len, user, false); + if (!ok) { + Len_Type old_valid_len = cache_valid_len - i; #if ASSERT_SRP_Fixed_CB - ASSERT_NE(old_valid_len, 0); + ASSERT_NE(old_valid_len, 0); #endif - state = Empty; - cache_valid_len = 0; - cache_packet_len = 0; - if (old_valid_len > 1) { - handle_new_recv_data(cache_buf + 1, old_valid_len - 1, user, true); - } - goto retry; - } - state = Empty; - cache_valid_len = 0; - cache_packet_len = 0; - - //handle_new_recv_data(cache_buf + 1, old_valid_len - 1, user, true); - - // TODO: - break; + state = Empty; + cache_valid_len = 0; + cache_packet_len = 0; + if (old_valid_len > 1) { + handle_new_recv_data(cache_buf + 1, old_valid_len - 1, user, true); } + goto retry; + } + state = Empty; + cache_valid_len = 0; + cache_packet_len = 0; + + // handle_new_recv_data(cache_buf + 1, old_valid_len - 1, user, true); + + // TODO: + break; } + } #if Debug_SRP_Fixed_CB - std::cout << "结束状态:" << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, cache_total_len) << std::endl; - std::cout << "cache_buf[" << cache_valid_len << "]:" << Psc::::mem2hex(std::string(cache_buf, cache_valid_len)) << std::endl; - std::cout << "=============== handle_with_old_buffer 退出! =============== " << std::endl; - std::cout << std::endl; + std::cout << "结束状态:" + << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, + cache_total_len) + << std::endl; + std::cout << "cache_buf[" << cache_valid_len + << "]:" << Psc:: ::mem2hex(std::string(cache_buf, cache_valid_len)) + << std::endl; + std::cout << "=============== handle_with_old_buffer 退出! =============== " + << std::endl; + std::cout << std::endl; #endif - return i; + return i; } template -bool Universal_Unpacker_Impl::handle_whole_packet(Buf_Type rcv_buf, Len_Type rcv_len, void* user, bool no_copy) { - bool ok = check ? check(rcv_buf, rcv_len, cur_skip_bytes) : true; - cur_skip_bytes = 0; +bool Universal_Unpacker_Impl::handle_whole_packet( + Buf_Type rcv_buf, Len_Type rcv_len, void *user, bool no_copy) { + bool ok = check ? check(rcv_buf, rcv_len, cur_skip_bytes) : true; + cur_skip_bytes = 0; #if Debug_SRP_Fixed_CB - printf("当前包长度:%u ", cache_packet_len); - if (no_copy) { - printf("无拷贝 rcv_len【%d】_", rcv_len); - } else { - printf("带拷贝 rcv_len【%d】_", rcv_len); - } + printf("当前包长度:%u ", cache_packet_len); + if (no_copy) { + printf("无拷贝 rcv_len【%d】_", rcv_len); + } else { + printf("带拷贝 rcv_len【%d】_", rcv_len); + } #endif - if (ok) { + if (ok) { #if Debug_SRP_Fixed_CB - std::cout << "crc校验成功的数据:" << Psc::::mem2hex(std::string((const char*)rcv_buf, rcv_len)) << std::endl; + std::cout << "crc校验成功的数据:" + << Psc:: ::mem2hex(std::string((const char *)rcv_buf, rcv_len)) + << std::endl; #endif - recv_call_back(rcv_buf, rcv_len, user); - } else { + recv_call_back(rcv_buf, rcv_len, user); + } else { #if Debug_SRP_Fixed_CB - std::cout << "crc校验失败的数据:" << Psc::::mem2hex(std::string((const char*)rcv_buf, rcv_len)) << std::endl; + std::cout << "crc校验失败的数据:" + << Psc:: ::mem2hex(std::string((const char *)rcv_buf, rcv_len)) + << std::endl; #endif - if (check_error_call_back) check_error_call_back(rcv_buf, rcv_len); - } - return ok; + if (check_error_call_back) + check_error_call_back(rcv_buf, rcv_len); + } + return ok; } - // 这个函数从0解析数据 template -void Universal_Unpacker_Impl::handle_new_recv_data(Buf_Type rcv_buf, Len_Type rcv_len, void* user, bool memmove) { +void Universal_Unpacker_Impl::handle_new_recv_data( + Buf_Type rcv_buf, Len_Type rcv_len, void *user, bool memmove) { #if ASSERT_SRP_Fixed_CB - ASSERT_EQ(state, Empty); - ASSERT_EQ(cache_valid_len, 0); + ASSERT_EQ(state, Empty); + ASSERT_EQ(cache_valid_len, 0); #endif - #if Debug_SRP_Fixed_CB - std::cout << "=============== handle_new_recv_data =================" << std::endl; - std::cout << "开始状态:" << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, cache_total_len) << std::endl; - std::cout << "cache_buf[" << cache_valid_len << "]:" << Psc::::mem2hex(std::string(cache_buf, cache_valid_len)) << std::endl; - std::cout << "rcv_buf[" << rcv_len << "]:" << Psc::::mem2hex(std::string(rcv_buf, rcv_len)) << std::endl; + std::cout << "=============== handle_new_recv_data =================" + << std::endl; + std::cout << "开始状态:" + << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, + cache_total_len) + << std::endl; + std::cout << "cache_buf[" << cache_valid_len + << "]:" << Psc:: ::mem2hex(std::string(cache_buf, cache_valid_len)) + << std::endl; + std::cout << "rcv_buf[" << rcv_len + << "]:" << Psc:: ::mem2hex(std::string(rcv_buf, rcv_len)) + << std::endl; #endif - Len_Type hdr_offset = 0; - while (true) { - Len_Type remain = rcv_len - hdr_offset; - Buf_Type cur_buf = rcv_buf + hdr_offset; + Len_Type hdr_offset = 0; + while (true) { + Len_Type remain = rcv_len - hdr_offset; + Buf_Type cur_buf = rcv_buf + hdr_offset; #if Debug_SRP_Fixed_CB - print_state("新数据while循环", this); + print_state("新数据while循环", this); #endif - if (state == Empty) { - if (rcv_len >= hdr_len) { - Len_Type hdr_max = rcv_len - hdr_len + 1; // 超过这个值还未找到包 就不可能找到完整的包头了 - for (; hdr_offset < hdr_max; hdr_offset++) { - if (mem_equal(rcv_buf + hdr_offset, hdr_buf, hdr_len)) { - state = Expect_Len; - break; - } - cur_skip_bytes++; - } - if (state == Expect_Len) { - continue; - } - } - // 不寻找完整的包头了 - for (; hdr_offset < rcv_len; hdr_offset++) { - Len_Type rl = rcv_len - hdr_offset; - cur_buf = rcv_buf + hdr_offset; -#if Debug_SRP_Fixed_CB - std::cout << VAR_STR_2(rl, hdr_offset) << std::endl; -#endif - if (mem_equal(cur_buf, hdr_buf, rl)) { - state = Expect_Hdr; - cache_valid_len = rl; - memcpy(cache_buf, hdr_buf, rl); - goto end; - } - cur_skip_bytes++; - } - if (hdr_offset == rcv_len) { - state = Empty; - cache_valid_len = 0; - goto end; - } - } else if (state == Expect_Hdr) { - Len_Type min = hdr_len; - if (mem_equal(cur_buf, hdr_buf, hdr_len)) { - state = Expect_Len; - } else { - state = Empty; - cache_valid_len = 0; - goto end; - } - } else if (state == Expect_Len) { - Len_Type need = len_offset + len_len; - if (remain < need) { - append_buffer(cur_buf, remain, memmove); - goto end; - } - if (!get_len) { - cache_packet_len = *reinterpret_cast(cur_buf + len_offset); - } else { - cache_packet_len = get_len(cur_buf + len_offset); - } -#if Debug_SRP_Fixed_CB - std::cout << "解析到长度:" << VAR_STR_2(hdr_offset, cache_packet_len) << std::endl; -#endif - if (cache_packet_len <= cache_total_len) { - state = Expect_All; - } else { - // 错误的长度 - if (len_error_call_back) len_error_call_back(rcv_buf, rcv_len); -#if Debug_SRP_Fixed_CB - std::cout << "【handle_new_recv_data 解析到错误的长度】" << VAR_STR_1(cache_packet_len) - << Psc::::mem2hex(std::string((char*)rcv_buf, rcv_len)) << std::endl; -#endif - hdr_offset++; - cur_skip_bytes = 1; - state = Empty; - cache_valid_len = 0; - cache_packet_len = 0; - } - } else if (state == Expect_All) { - Len_Type need = cache_packet_len; - if (remain < need) { - append_buffer(cur_buf, remain, memmove); - goto end; - } - bool ok = handle_whole_packet(cur_buf, cache_packet_len, user, true); - if (ok) { - hdr_offset += cache_packet_len; - } else { - hdr_offset++; // 概率误判包头 跳一个继续找 - - } - - state = Empty; - cache_valid_len = 0; + if (state == Empty) { + if (rcv_len >= hdr_len) { + Len_Type hdr_max = rcv_len - hdr_len + + 1; // 超过这个值还未找到包 就不可能找到完整的包头了 + for (; hdr_offset < hdr_max; hdr_offset++) { + if (mem_equal(rcv_buf + hdr_offset, hdr_buf, hdr_len)) { + state = Expect_Len; + break; + } + cur_skip_bytes++; } - } - end: + if (state == Expect_Len) { + continue; + } + } + // 不寻找完整的包头了 + for (; hdr_offset < rcv_len; hdr_offset++) { + Len_Type rl = rcv_len - hdr_offset; + cur_buf = rcv_buf + hdr_offset; #if Debug_SRP_Fixed_CB - std::cout << "结束状态:" << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, cache_total_len) << std::endl; - std::cout << "cache_buf[" << cache_valid_len << "]:" << Psc::::mem2hex(std::string(cache_buf, cache_valid_len)) << std::endl; - std::cout << "=============== handle_new_recv_data 退出! =============== " << std::endl; - std::cout << std::endl; + std::cout << VAR_STR_2(rl, hdr_offset) << std::endl; #endif - return; + if (mem_equal(cur_buf, hdr_buf, rl)) { + state = Expect_Hdr; + cache_valid_len = rl; + memcpy(cache_buf, hdr_buf, rl); + goto end; + } + cur_skip_bytes++; + } + if (hdr_offset == rcv_len) { + state = Empty; + cache_valid_len = 0; + goto end; + } + } else if (state == Expect_Hdr) { + Len_Type min = hdr_len; + if (mem_equal(cur_buf, hdr_buf, hdr_len)) { + state = Expect_Len; + } else { + state = Empty; + cache_valid_len = 0; + goto end; + } + } else if (state == Expect_Len) { + Len_Type need = len_offset + len_len; + if (remain < need) { + append_buffer(cur_buf, remain, memmove); + goto end; + } + if (!get_len) { + cache_packet_len = *reinterpret_cast(cur_buf + len_offset); + } else { + cache_packet_len = get_len(cur_buf + len_offset); + } +#if Debug_SRP_Fixed_CB + std::cout << "解析到长度:" << VAR_STR_2(hdr_offset, cache_packet_len) + << std::endl; +#endif + if (cache_packet_len <= cache_total_len) { + state = Expect_All; + } else { + // 错误的长度 + if (len_error_call_back) + len_error_call_back(rcv_buf, rcv_len); +#if Debug_SRP_Fixed_CB + std::cout << "【handle_new_recv_data 解析到错误的长度】" + << VAR_STR_1(cache_packet_len) + << Psc:: ::mem2hex(std::string((char *)rcv_buf, rcv_len)) + << std::endl; +#endif + hdr_offset++; + cur_skip_bytes = 1; + state = Empty; + cache_valid_len = 0; + cache_packet_len = 0; + } + } else if (state == Expect_All) { + Len_Type need = cache_packet_len; + if (remain < need) { + append_buffer(cur_buf, remain, memmove); + goto end; + } + bool ok = handle_whole_packet(cur_buf, cache_packet_len, user, true); + if (ok) { + hdr_offset += cache_packet_len; + } else { + hdr_offset++; // 概率误判包头 跳一个继续找 + } + + state = Empty; + cache_valid_len = 0; + } + } +end: +#if Debug_SRP_Fixed_CB + std::cout << "结束状态:" + << VAR_STR_5(state, rcv_len, cache_valid_len, cache_packet_len, + cache_total_len) + << std::endl; + std::cout << "cache_buf[" << cache_valid_len + << "]:" << Psc:: ::mem2hex(std::string(cache_buf, cache_valid_len)) + << std::endl; + std::cout << "=============== handle_new_recv_data 退出! =============== " + << std::endl; + std::cout << std::endl; +#endif + return; } template -void Universal_Unpacker_Impl::push_data(Buf_Type rcv_buf, Len_Type rcv_len, void* user) { +void Universal_Unpacker_Impl::push_data(Buf_Type rcv_buf, + Len_Type rcv_len, + void *user) { #if Debug_SRP_Fixed_CB - auto old_valid_len = cache_valid_len; + auto old_valid_len = cache_valid_len; #endif - Len_Type i = 0; - if (state != Empty) { - i = handle_with_old_buffer(rcv_buf, rcv_len, user); - } + Len_Type i = 0; + if (state != Empty) { + i = handle_with_old_buffer(rcv_buf, rcv_len, user); + } #if Debug_SRP_Fixed_CB - printf("【Universal_Unpacker::recv】 缓冲区长度【%d】 新数据长度【%d】 已处理旧包使用了【%d】 处理完旧包,还需处理【%d】字节数据\r\n", - old_valid_len, rcv_len, i, rcv_len > i ? rcv_len - i : 0); + printf("【Universal_Unpacker::recv】 缓冲区长度【%d】 新数据长度【%d】 " + "已处理旧包使用了【%d】 处理完旧包,还需处理【%d】字节数据\r\n", + old_valid_len, rcv_len, i, rcv_len > i ? rcv_len - i : 0); #endif - if (rcv_len > i) { - handle_new_recv_data(rcv_buf + i, rcv_len - i, user, false); - } else { - } + if (rcv_len > i) { + handle_new_recv_data(rcv_buf + i, rcv_len - i, user, false); + } else { + } #if ASSERT_SRP_Fixed_CB - ASSERT_LE(cache_valid_len, cache_total_len); + ASSERT_LE(cache_valid_len, cache_total_len); #endif } -} +} // namespace Psc diff --git a/Core/transmit_protocol/other_node/udp_serial.cpp b/Core/transmit_protocol/other_node/udp_serial.cpp index 8d43f0d..50c1145 100644 --- a/Core/transmit_protocol/other_node/udp_serial.cpp +++ b/Core/transmit_protocol/other_node/udp_serial.cpp @@ -1,170 +1,170 @@ #include "./udp_serial.h" #include -UDP_Serial::~UDP_Serial() { - g_free(buffer); +UDP_Serial::~UDP_Serial() { g_free(buffer); } + +UDP_Serial::UDP_Serial(Len_Type ring_buffer_size, IUINT32 header, bool use_crc) + : header(header), use_crc(use_crc), buffer_size(ring_buffer_size) { + buffer = static_cast(g_malloc(ring_buffer_size)); + s_pos = 0; + e_pos = 0; + hdr_len = sizeof(UDP_Serial_Packet_Header); + if (use_crc == false) { + hdr_len -= sizeof(static_cast(nullptr)->crc); + } } +void UDP_Serial::send(Buf_Type data, Len_Type len, void *user) { + IUINT32 total_len = hdr_len + len; + char *buf = (char *)g_malloc(total_len); + memcpy(buf + hdr_len, data, len); + auto h = reinterpret_cast(buf); + h->header = header; + h->data_len = len; + if (use_crc) { -UDP_Serial::UDP_Serial(Len_Type ring_buffer_size, IUINT32 header, bool use_crc) : header(header), use_crc(use_crc), buffer_size(ring_buffer_size) { - buffer = static_cast(g_malloc(ring_buffer_size)); - s_pos = 0; - e_pos = 0; - hdr_len = sizeof(UDP_Serial_Packet_Header); - if (use_crc == false) { - hdr_len -= sizeof(static_cast(nullptr)->crc); - } + h->crc = CRC_FUNC(buf + hdr_len - sizeof(Len_Type), len + sizeof(Len_Type)); + } + next_send(this, buf, total_len, user); + g_free(buf); } - -void UDP_Serial::send(Buf_Type data, Len_Type len, void* user) { - IUINT32 total_len = hdr_len + len; - char* buf = (char*)g_malloc(total_len); - memcpy(buf + hdr_len, data, len); - auto h = reinterpret_cast(buf); - h->header = header; - h->data_len = len; - if (use_crc) { - - h->crc = CRC_FUNC(buf + hdr_len - sizeof(Len_Type), len + sizeof(Len_Type)); - } - next_send(this, buf, total_len, user); - g_free(buf); +bool UDP_Serial::check_crc(UDP_Serial_Packet_Header *hdr) const { + CRC_Type crc_calc = + CRC_FUNC((void *)((uint8_t *)hdr + hdr_len - sizeof(Len_Type)), + hdr->data_len + sizeof(Len_Type)); + return (crc_calc == hdr->crc); } - -bool UDP_Serial::check_crc(UDP_Serial_Packet_Header* hdr) const { - CRC_Type crc_calc = CRC_FUNC((void*)((uint8_t*)hdr + hdr_len - sizeof(Len_Type)), hdr->data_len + sizeof(Len_Type)); - return (crc_calc == hdr->crc); -} - - - // 一个完整的recv 状态转换 // 解析到包头 需要的长度 recv剩余长度 - - - - -// 应该是 大数据包时 len > buffer_size 直接在 参数buf里找到第一个头 给缓冲区进行拼接处理 然后 置空 s_pos e_pos -// 剩余部分直接 解析 buf 解析完的剩余部分 拷贝到 buffer size 然后恢复s_pos e_pos - +// 应该是 大数据包时 len > buffer_size 直接在 参数buf里找到第一个头 +// 给缓冲区进行拼接处理 然后 置空 s_pos e_pos 剩余部分直接 解析 buf +// 解析完的剩余部分 拷贝到 buffer size 然后恢复s_pos e_pos // 外部保证 data_len小于缓冲区的大小, 如果超过代表误码 或者发送端使用错误 -// 逻辑应该是 找header 读取长度 等待长度 校验数据 校验成功 pos+len 校验失败 继续找下一个pos +// 逻辑应该是 找header 读取长度 等待长度 校验数据 校验成功 pos+len 校验失败 +// 继续找下一个pos +void UDP_Serial::recv(Buf_Type buf, Len_Type len, void *user) { + // 1. 如果缓冲区里有残留,先拼接 + if (e_pos > s_pos) { + recv_to_buffer(buf, len, user); + return; + } + // 2. 大数据包情况 + if (len > buffer_size) { + // 2.1 先把第一个包头 + 部分数据拼进 buffer + int first_copy = hdr_len; // 最少要把头放进去 + if (first_copy > buffer_size) { + s_pos = e_pos = 0; + return; + } -void UDP_Serial::recv(Buf_Type buf, Len_Type len, void* user) { - // 1. 如果缓冲区里有残留,先拼接 - if (e_pos > s_pos) { + memcpy(buffer, buf, first_copy); + s_pos = 0; + e_pos = first_copy; + + // 用 buffer 逻辑解析(可能没收齐,停在半包) + recv_to_buffer(nullptr, 0, user); + + // 更新 buf 指针,跳过已拷贝的部分 + buf += first_copy; + len -= first_copy; + + // 2.2 直接解析 buf 剩余部分(零拷贝) + while (len >= hdr_len) { + auto p = reinterpret_cast(buf); + auto hdr = &p->header; + + if (hdr->header != header || hdr->data_len + hdr_len > buffer_size) { + // 遇到异常 -> 进入 buffer 模式 recv_to_buffer(buf, len, user); return; - } + } - // 2. 大数据包情况 - if (len > buffer_size) { - // 2.1 先把第一个包头 + 部分数据拼进 buffer - int first_copy = hdr_len; // 最少要把头放进去 - if (first_copy > buffer_size) { s_pos = e_pos = 0; return; } - - memcpy(buffer, buf, first_copy); - s_pos = 0; - e_pos = first_copy; - - // 用 buffer 逻辑解析(可能没收齐,停在半包) - recv_to_buffer(nullptr, 0, user); - - // 更新 buf 指针,跳过已拷贝的部分 - buf += first_copy; - len -= first_copy; - - // 2.2 直接解析 buf 剩余部分(零拷贝) - while (len >= hdr_len) { - auto p = reinterpret_cast(buf); - auto hdr = &p->header; - - if (hdr->header != header || hdr->data_len + hdr_len > buffer_size) { - // 遇到异常 -> 进入 buffer 模式 - recv_to_buffer(buf, len, user); - return; - } - - if (len < hdr_len + hdr->data_len) { - // 半包 -> 存到 buffer - recv_to_buffer(buf, len, user); - return; - } - - if (use_crc && !check_crc(hdr)) { - buf++; len--; - continue; - } - - next_recv(this, reinterpret_cast(p) + hdr_len, hdr->data_len, user); - - buf += hdr_len + hdr->data_len; - len -= hdr_len + hdr->data_len; - } - - // 2.3 最后的小尾巴也进 buffer - if (len > 0) { - recv_to_buffer(buf, len, user); - } + if (len < hdr_len + hdr->data_len) { + // 半包 -> 存到 buffer + recv_to_buffer(buf, len, user); return; + } + + if (use_crc && !check_crc(hdr)) { + buf++; + len--; + continue; + } + + next_recv(this, reinterpret_cast(p) + hdr_len, hdr->data_len, + user); + + buf += hdr_len + hdr->data_len; + len -= hdr_len + hdr->data_len; } - // 3. 普通情况(len <= buffer_size) - recv_to_buffer(buf, len, user); + // 2.3 最后的小尾巴也进 buffer + if (len > 0) { + recv_to_buffer(buf, len, user); + } + return; + } + + // 3. 普通情况(len <= buffer_size) + recv_to_buffer(buf, len, user); } +void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void *user) { + if (len > buffer_size) { + printf("【严重错误】len[%u] > SERIAL_BUF_SIZE[%u]\n", len, buffer_size); + return; + } -void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void* user) { - if (len > buffer_size) { - printf("【严重错误】len[%u] > SERIAL_BUF_SIZE[%u]\n", len, buffer_size); - return; + // 搬移,保证尾部有空间 + if (len > buffer_size - (e_pos - s_pos)) { + IUINT32 valid_len = e_pos - s_pos; + if (valid_len > 0) + memmove(buffer, buffer + s_pos, valid_len); + s_pos = 0; + e_pos = valid_len; + if (len > buffer_size - e_pos) { + s_pos = e_pos = 0; + return; + } + } + + memcpy(buffer + e_pos, buf, len); + e_pos += len; + + while (e_pos - s_pos >= hdr_len) { + auto p = reinterpret_cast(buffer + s_pos); + auto hdr = &p->header; + + if (hdr->header != header || hdr->data_len + hdr_len > buffer_size) { + if (++s_pos >= e_pos) + s_pos = e_pos = 0; + continue; } - // 搬移,保证尾部有空间 - if (len > buffer_size - (e_pos - s_pos)) { - IUINT32 valid_len = e_pos - s_pos; - if (valid_len > 0) memmove(buffer, buffer + s_pos, valid_len); - s_pos = 0; - e_pos = valid_len; - if (len > buffer_size - e_pos) { s_pos = e_pos = 0; return; } + if (e_pos - s_pos < hdr_len + hdr->data_len) + break; + + if (use_crc && !check_crc(hdr)) { + if (++s_pos >= e_pos) + s_pos = e_pos = 0; + continue; } - memcpy(buffer + e_pos, buf, len); - e_pos += len; + next_recv(this, reinterpret_cast(p) + hdr_len, hdr->data_len, + user); + s_pos += hdr_len + hdr->data_len; + } - while (e_pos - s_pos >= hdr_len) { - auto p = reinterpret_cast(buffer + s_pos); - auto hdr = &p->header; - - if (hdr->header != header || hdr->data_len + hdr_len > buffer_size) { - if (++s_pos >= e_pos) s_pos = e_pos = 0; - continue; - } - - if (e_pos - s_pos < hdr_len + hdr->data_len) break; - - if (use_crc && !check_crc(hdr)) { - if (++s_pos >= e_pos) s_pos = e_pos = 0; - continue; - } - - next_recv(this, reinterpret_cast(p) + hdr_len, hdr->data_len, user); - s_pos += hdr_len + hdr->data_len; - } - - if (s_pos == e_pos) s_pos = e_pos = 0; + if (s_pos == e_pos) + s_pos = e_pos = 0; } - - - - // void UDP_Serial::recv(Buf_Type buf, Len_Type len, void* user) { // while (len > 0) { // // 剩余空间 @@ -203,7 +203,8 @@ void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void* user) { // auto p = reinterpret_cast(buffer + s_pos); // auto hdr = &p->header; // -// if (hdr->header != header || hdr->data_len + hdr_len > buffer_size) { +// if (hdr->header != header || hdr->data_len + hdr_len > +// buffer_size) { // if (++s_pos >= e_pos) s_pos = e_pos = 0; // continue; // } @@ -215,8 +216,8 @@ void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void* user) { // continue; // } // -// next_recv(this, reinterpret_cast(p) + hdr_len, hdr->data_len, user); -// s_pos += hdr_len + hdr->data_len; +// next_recv(this, reinterpret_cast(p) + hdr_len, +// hdr->data_len, user); s_pos += hdr_len + hdr->data_len; // } // // if (s_pos == e_pos) s_pos = e_pos = 0; @@ -233,8 +234,9 @@ void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void* user) { // void UDP_Serial::recv(Buf_Type buf, Len_Type len, void* user) { // // 最大包大小不能超过缓冲区的最大大小 // if (len > buffer_size) { -// printf("【严重错误:这里传入的是完整的包,大小不能超缓冲区】serial input error len[%u] > SERIAL_BUF_SIZE:[%u] too short!\n", len, buffer_size); -// return; // 不要 exit,避免整个程序挂掉 +// printf("【严重错误:这里传入的是完整的包,大小不能超缓冲区】serial +// input error len[%u] > SERIAL_BUF_SIZE:[%u] too short!\n", len, +// buffer_size); return; // 不要 exit,避免整个程序挂掉 // } // // size_t free_space = buffer_size - (e_pos - s_pos); @@ -242,13 +244,14 @@ void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void* user) { // move_data_to_head(this); // } // if (len > buffer_size - e_pos) { -// // 此时要么是data_len字段异常, 要么是发送端发送长度超过缓冲区了 必须丢掉 -// if (e_pos - s_pos >= hdr_len) { -// auto hdr = reinterpret_cast(buffer + s_pos); -// IUINT32 total_len = hdr_len + hdr->data_len; +// // 此时要么是data_len字段异常, 要么是发送端发送长度超过缓冲区了 +// 必须丢掉 if (e_pos - s_pos >= hdr_len) { +// auto hdr = reinterpret_cast(buffer + +// s_pos); IUINT32 total_len = hdr_len + hdr->data_len; // print_serial_cb_state2("", this); -// printf("【严重错误】wait for length total_len:[%u] data_len:[%u] ", total_len, hdr->data_len); -// printf("添加不进数据 len:[%u] 越界??? 或者数据错误!丢弃这一组! \r\n\n", len); +// printf("【严重错误】wait for length total_len:[%u] data_len:[%u] +// ", total_len, hdr->data_len); printf("添加不进数据 len:[%u] +// 越界??? 或者数据错误!丢弃这一组! \r\n\n", len); // } // s_pos = 0; // e_pos = 0; @@ -275,66 +278,59 @@ void UDP_Serial::recv_to_buffer(Buf_Type buf, Len_Type len, void* user) { // continue; // } // if (e_pos - s_pos - hdr_len < hdr->data_len) { -// //printf(" wait for length total_len:[%u] data_len:[%u] \r\n", total_len, hdr->data_len); -// break; // 数据没到齐,等下一批 +// //printf(" wait for length total_len:[%u] data_len:[%u] +// \r\n", total_len, hdr->data_len); break; // 数据没到齐,等下一批 // } // if (use_crc == true) { // if (!UDP_Serial_check_crc(hdr)) { // //print_serial_cb_state(cb); -// //printf(" crc错误放弃这个开头??? 或者数据错误!丢弃这一组! \r\n"); -// s_pos++; // 丢弃一个字节,继续找 MAGIC -// continue; +// //printf(" crc错误放弃这个开头??? +// 或者数据错误!丢弃这一组! \r\n"); s_pos++; // +// 丢弃一个字节,继续找 MAGIC continue; // } // } -// next_recv(this, reinterpret_cast(p) + hdr_len, hdr->data_len, user); +// next_recv(this, reinterpret_cast(p) + hdr_len, +// hdr->data_len, user); // // 这里不会溢出 前面异常长度已经判断掉了 // s_pos += hdr_len + hdr->data_len; // } // } - - struct State { - bool hdr_ok = false; - bool len_ok = false; - bool crc_ok = false; - Len_Type hdr_offset{}, hdr_size{}; - Len_Type len_offset{}, len_size{}; - Len_Type crc_offset{}, crc_size{}; - Len_Type buf_len{}; - Buf_Type buf{}; - Len_Type max_len; + bool hdr_ok = false; + bool len_ok = false; + bool crc_ok = false; + Len_Type hdr_offset{}, hdr_size{}; + Len_Type len_offset{}, len_size{}; + Len_Type crc_offset{}, crc_size{}; + Len_Type buf_len{}; + Buf_Type buf{}; + Len_Type max_len; + Len_Type packet_len() const { + return *reinterpret_cast(buf + len_offset); + } - Len_Type packet_len() const { - return *reinterpret_cast(buf + len_offset); + virtual bool check_hdr(Buf_Type hdr) { return true; } + + void handle_in_hdr_ok(Buf_Type frame, Len_Type len) { + // frame + len_offset + } + + void handle_in_hdr_not_ok(Buf_Type buf, Len_Type &remain) { + for (Len_Type i = 0; i < remain; ++i) { + Buf_Type cur = buf + i; + if (check_hdr(cur)) { + hdr_ok = true; + handle_in_hdr_ok(cur, remain - i); + break; + } } + } - virtual bool check_hdr(Buf_Type hdr) { - return true; - } - - - - - void handle_in_hdr_ok(Buf_Type frame, Len_Type len) { - //frame + len_offset - } - - void handle_in_hdr_not_ok(Buf_Type buf, Len_Type& remain) { - for (Len_Type i = 0; i < remain; ++i) { - Buf_Type cur = buf + i; - if (check_hdr(cur)) { - hdr_ok = true; - handle_in_hdr_ok(cur, remain - i); - break; - } - } - } - - void recv(Buf_Type buf, Len_Type& remain) { - if (!hdr_ok) { - handle_in_hdr_not_ok(buf, remain); - } + void recv(Buf_Type buf, Len_Type &remain) { + if (!hdr_ok) { + handle_in_hdr_not_ok(buf, remain); } + } }; \ No newline at end of file diff --git a/Core/transmit_protocol/other_node/udp_serial.mermaid b/Core/transmit_protocol/other_node/udp_serial.mermaid index ab7257f..4aa8a51 100644 --- a/Core/transmit_protocol/other_node/udp_serial.mermaid +++ b/Core/transmit_protocol/other_node/udp_serial.mermaid @@ -44,35 +44,29 @@ stateDiagram-v2 %% rl --> rh %% rl --> crc: "长度足够" %% crc --> call_back + [*] --> recv_data - - -[*] --> recv_data - -state recv_data { - [*] --> buf: "头指针" - [*] --> len: "长度" - [*] --> left: "置零" - [*] --> right: "置零" - state inter_sm{ - [*] --> cache: "内部缓冲区" - [*] --> cache_len: "内部缓冲区长度" - [*] --> have_hdr: "是否读取到头" - [*] --> hdr_offset: "头偏移" - [*] --> have_len: "是否读取到长度" - [*] --> len_offset: "长度偏移" - [*] --> have_crc: "是否读取到crc" - [*] --> crc_offset: "crc偏移" + state recv_data { + [*] --> buf: "头指针" + [*] --> len: "长度" + [*] --> left: "置零" + [*] --> right: "置零" + state inter_sm { + [*] --> cache: "内部缓冲区" + [*] --> cache_len: "内部缓冲区长度" + [*] --> have_hdr: "是否读取到头" + [*] --> hdr_offset: "头偏移" + [*] --> have_len: "是否读取到长度" + [*] --> len_offset: "长度偏移" + [*] --> have_crc: "是否读取到crc" + [*] --> crc_offset: "crc偏移" + } } -} - - -recv_data --> rh -rh --> rl: "读取到长度" -rl --> recv_data: "长度大于缓冲区上限丢弃" -rl --> check: "长度足够" -check --> call_back - + recv_data --> rh + rh --> rl: "读取到长度" + rl --> recv_data: "长度大于缓冲区上限丢弃" + rl --> check: "长度足够" + check --> call_back %% 来了新数据 如果内部缓冲区 diff --git a/Core/transmit_protocol/udp_fec_s/global.h b/Core/transmit_protocol/udp_fec_s/global.h index deeb91e..fbedc1b 100644 --- a/Core/transmit_protocol/udp_fec_s/global.h +++ b/Core/transmit_protocol/udp_fec_s/global.h @@ -1,11 +1,10 @@ #pragma once - namespace Psc { -// TODO: 这个起名是表明 这个FEC 有UDP的特征,单包 不可靠特性,特别的一点 依赖底层传输的顺序性 -// 基于 包式 局部可靠 顺序 丢包的 协议 -// 生成一个 流式 局部可靠 顺序 丢数据的 协议 但是增加了 fec编码 实现了流量换可靠性 +// TODO: 这个起名是表明 这个FEC 有UDP的特征,单包 不可靠特性,特别的一点 +// 依赖底层传输的顺序性 基于 包式 局部可靠 顺序 丢包的 协议 生成一个 +// 流式 局部可靠 顺序 丢数据的 协议 但是增加了 fec编码 实现了流量换可靠性 #define recv_debug true typedef struct UDP_FEC_CB UDP_FEC_CB; typedef struct UDP_FEC_Packet UDP_FEC_Packet; @@ -16,37 +15,38 @@ typedef struct UDP_FEC_Packet_state UDP_FEC_Packet_state; enum UDP_FEC_Packet_type { UDP_FEC_CB_Data_Packet, UDP_FEC_Channel_State }; #define FEC_Base_Packet_Content IUINT8 type; struct UDP_FEC_Base_Packet { - FEC_Base_Packet_Content + FEC_Base_Packet_Content }; struct UDP_FEC_Packet_Header { - FEC_Base_Packet_Content Packet_Seq_Type seq; - Len_Type total_len; + FEC_Base_Packet_Content Packet_Seq_Type seq; + Len_Type total_len; }; struct UDP_FEC_Packet_state { - FEC_Base_Packet_Content - IUINT16 code_rate; // 码率 - IUINT16 single_packet_success; // 单包接收成功率 - IUINT16 whole_packet_success; // 整体包接收成功率 - IUINT16 decode_packet_success; // fec解码成功率 + FEC_Base_Packet_Content IUINT16 code_rate; // 码率 + IUINT16 single_packet_success; // 单包接收成功率 + IUINT16 whole_packet_success; // 整体包接收成功率 + IUINT16 decode_packet_success; // fec解码成功率 }; -void UDP_FEC_Packet_state_send(UDP_FEC_CB* cb); +void UDP_FEC_Packet_state_send(UDP_FEC_CB *cb); struct UDP_FEC_Packet { - UDP_FEC_Packet_Header header; - char* data; + UDP_FEC_Packet_Header header; + char *data; }; extern const Len_Type fec_packet_header_len; extern const Len_Type fec_header_len; -void print_dec_state(void* tcb); -void decode_writer(fec_decoder* dec, void* userData, IINT64 pos, fecPayload* buf, __int32_t len); +void print_dec_state(void *tcb); +void decode_writer(fec_decoder *dec, void *userData, IINT64 pos, + fecPayload *buf, __int32_t len); struct Data_Frame_Type { - Len_Type seq; - Len_Type size; - Len_Type i, n, k, s; - Buf_Type data; + Len_Type seq; + Len_Type size; + Len_Type i, n, k, s; + Buf_Type data; }; -void Data_Frame_Type_release(void* ptr); -Data_Frame_Type* Data_Frame_Type_create(Len_Type seq, Len_Type i, Len_Type n, Len_Type k, Len_Type s, Buf_Type buf, +void Data_Frame_Type_release(void *ptr); +Data_Frame_Type *Data_Frame_Type_create(Len_Type seq, Len_Type i, Len_Type n, + Len_Type k, Len_Type s, Buf_Type buf, Len_Type len); -} +} // namespace Psc diff --git a/Core/transmit_protocol/udp_fec_s/udp_fec.h b/Core/transmit_protocol/udp_fec_s/udp_fec.h index 6c90e80..cde830c 100644 --- a/Core/transmit_protocol/udp_fec_s/udp_fec.h +++ b/Core/transmit_protocol/udp_fec_s/udp_fec.h @@ -1,48 +1,46 @@ #ifndef UDP_FEC_H #define UDP_FEC_H +#include "../../../Core/Statistics/Statistics.h" #include "../feclib/fec.h" #include "../global.h" -#include "../../../Core/Statistics/Statistics.h" #include "global.h" namespace Psc { struct UDP_FEC_CB : Base_CB { - void print_state_info() override; - // 发送端 - fec_encoder* enc{}; - IUINT32 send_seq = 0; - DL* send_data_list{}; - double redundancy = 0.5; // 冗余度 冗余片占所有片的比例 - // 接收端 - fec_decoder* dec{}; - Packet_Seq_Type last_seq = 0; - Ptr_List* decode_origin_list{}; - Ptr_List* decode_cache_list{}; - // 每一个包有自己的设置 每一个新包 这个设置清空 - bool init = false; - bool* idx_array{}; - char* recv_buffer{}; - Len_Type s{}; - Len_Type n{}; - Len_Type k{}; - Len_Type total_len{}; - Get_Millisecond get_millisecond{}; - // 信道状态字段 - Probability_Statistics code_rate{}; // 码率 - Probability_Statistics single_packet_success{}; // 单包接收成功率 - Probability_Statistics whole_packet_success{}; // 整体包接收成功率 - Probability_Statistics decode_packet_success{}; // fec解码成功率 - IUINT32 send_state_time_millisecond_interval = 1000; - IUINT32 send_state_time_last_time{}; - explicit UDP_FEC_CB(Get_Millisecond get_millisecond); - ~UDP_FEC_CB() override; - void send(Buf_Type buf, Len_Type len, void* user) override; - void recv(Buf_Type buf, Len_Type len, void* user) override; + void print_state_info() override; + // 发送端 + fec_encoder *enc{}; + IUINT32 send_seq = 0; + DL *send_data_list{}; + double redundancy = 0.5; // 冗余度 冗余片占所有片的比例 + // 接收端 + fec_decoder *dec{}; + Packet_Seq_Type last_seq = 0; + Ptr_List *decode_origin_list{}; + Ptr_List *decode_cache_list{}; + // 每一个包有自己的设置 每一个新包 这个设置清空 + bool init = false; + bool *idx_array{}; + char *recv_buffer{}; + Len_Type s{}; + Len_Type n{}; + Len_Type k{}; + Len_Type total_len{}; + Get_Millisecond get_millisecond{}; + // 信道状态字段 + Probability_Statistics code_rate{}; // 码率 + Probability_Statistics single_packet_success{}; // 单包接收成功率 + Probability_Statistics whole_packet_success{}; // 整体包接收成功率 + Probability_Statistics decode_packet_success{}; // fec解码成功率 + IUINT32 send_state_time_millisecond_interval = 1000; + IUINT32 send_state_time_last_time{}; + explicit UDP_FEC_CB(Get_Millisecond get_millisecond); + ~UDP_FEC_CB() override; + void send(Buf_Type buf, Len_Type len, void *user) override; + void recv(Buf_Type buf, Len_Type len, void *user) override; }; - - // 无用函数 仅仅用于测试 void test_calc_snk_all(); -} +} // namespace Psc #endif diff --git a/Core/transmit_protocol/udp_fec_s/udp_fec_recv.cpp b/Core/transmit_protocol/udp_fec_s/udp_fec_recv.cpp index 3791bb8..a04ed82 100644 --- a/Core/transmit_protocol/udp_fec_s/udp_fec_recv.cpp +++ b/Core/transmit_protocol/udp_fec_s/udp_fec_recv.cpp @@ -1,271 +1,277 @@ #include "udp_fec.h" namespace Psc { -void decode_writer(fec_decoder* dec, void* userData, IINT64 pos, fecPayload* buf, __int32_t len) { - UDP_FEC_CB* cb = (UDP_FEC_CB*)userData; - - - //Probability_Statistics_update(&cb->single_packet_success, true); +void decode_writer(fec_decoder *dec, void *userData, IINT64 pos, + fecPayload *buf, __int32_t len) { + UDP_FEC_CB *cb = (UDP_FEC_CB *)userData; + // Probability_Statistics_update(&cb->single_packet_success, true); #ifdef Packet_0_9_check_enable - int it = check_cycle_0_9((char*)buf, 400); - if (it != 0) { - printf("恢复错误 decode_writer check 0-9 error %d \r\n", it); - exit(12345); - } + int it = check_cycle_0_9((char *)buf, 400); + if (it != 0) { + printf("恢复错误 decode_writer check 0-9 error %d \r\n", it); + exit(12345); + } #endif - IINT64 idx = pos / dec->e->s; - if (recv_debug) { - printf("decode_writer idx:%lld[%lld,%u] \r\n", idx, pos, len); - // push_mem(cb->recv_data_list, (Buf_Type)buf, len); - } - // IINT64 idx, - cb->idx_array[idx] = true; - memmove(cb->recv_buffer + pos, buf, len); + IINT64 idx = pos / dec->e->s; + if (recv_debug) { + printf("decode_writer idx:%lld[%lld,%u] \r\n", idx, pos, len); + // push_mem(cb->recv_data_list, (Buf_Type)buf, len); + } + // IINT64 idx, + cb->idx_array[idx] = true; + memmove(cb->recv_buffer + pos, buf, len); } -void flush_recv_decode(UDP_FEC_CB* cb, void* user) { - Len_Type n = cb->n; - Len_Type k = cb->k; - Len_Type s = cb->s; - Len_Type rn = cb->decode_origin_list->len; - Len_Type rk = cb->decode_cache_list->len; - IUINT16 buffer_size = s * n; - IUINT16 t = s/16; - cb->code_rate.update(n * t); - cb->code_rate.update( -k * t); - cb->single_packet_success.update(rn + rk); - cb->single_packet_success.update(-(n + k - rn - rk)); +void flush_recv_decode(UDP_FEC_CB *cb, void *user) { + Len_Type n = cb->n; + Len_Type k = cb->k; + Len_Type s = cb->s; + Len_Type rn = cb->decode_origin_list->len; + Len_Type rk = cb->decode_cache_list->len; + IUINT16 buffer_size = s * n; + IUINT16 t = s / 16; + cb->code_rate.update(n * t); + cb->code_rate.update(-k * t); + cb->single_packet_success.update(rn + rk); + cb->single_packet_success.update(-(n + k - rn - rk)); + if (recv_debug) { + printf("【%d】 s:%d n:%d k:%d rn:%d rk:%d cur_total_len:%d \r\n", + cb->last_seq, s, n, k, rn, rk, cb->total_len); + } + if (rn == n) { if (recv_debug) { - printf("【%d】 s:%d n:%d k:%d rn:%d rk:%d cur_total_len:%d \r\n", cb->last_seq, s, n, k, rn, rk, cb->total_len); + printf(" 收到全部帧 原始帧数%d 恢复帧数%d \n", rn, rk); } - if (rn == n) { - if (recv_debug) { - printf(" 收到全部帧 原始帧数%d 恢复帧数%d \n", rn, rk); - } - char* total = (Buf_Type)g_malloc(buffer_size); - Len_Type cur = 0; - Ptr_Node* t = cb->decode_origin_list->head; + char *total = (Buf_Type)g_malloc(buffer_size); + Len_Type cur = 0; + Ptr_Node *t = cb->decode_origin_list->head; + while (t) { + Data_Frame_Type *d = (Data_Frame_Type *)t->ptr; + Len_Type origin_data_size = d->size - fec_header_len; + char *data = d->data + fec_header_len; + PSC_ASSERT(origin_data_size == s, ""); + memmove(total + cur, data, origin_data_size); + cur += origin_data_size; + t = t->next; + } + if (cur != buffer_size) { + printf("11122 cur[%d] cb->cur_total_len:[%d] \n", cur, cb->total_len); + exit(11122); + } + cb->next_recv((Base_CB *)cb, total, cb->total_len, user); + g_free(total); + cb->whole_packet_success.update(true); + } else { // 需要恢复 + if (rn + rk >= n) { // 具备恢复条件 + cb->recv_buffer = (Buf_Type)g_malloc(buffer_size); + cb->idx_array = (bool *)g_malloc(n); + for (IUINT16 i = 0; i < n; i++) { + cb->idx_array[i] = false; + } + { + // 添加原始数据 + Ptr_Node *t = cb->decode_origin_list->head; while (t) { - Data_Frame_Type* d = (Data_Frame_Type*)t->ptr; - Len_Type origin_data_size = d->size - fec_header_len; - char* data = d->data + fec_header_len; - PSC_ASSERT(origin_data_size == s, ""); - memmove(total + cur, data, origin_data_size); - cur += origin_data_size; - t = t->next; + Data_Frame_Type *d = (Data_Frame_Type *)t->ptr; + cb->idx_array[d->i] = true; + Len_Type len = d->size - fec_header_len; + char *data = d->data + fec_header_len; + PSC_ASSERT(len == s, ""); + PSC_ASSERT(d->i < n, ""); + IUINT16 idx = d->i * s; + PSC_ASSERT(idx + len <= buffer_size, ""); + if (recv_debug) { + printf("origin_writer idx:%u[%u,%u] \r\n", d->i, idx, len); + // push_mem(cb->recv_data_list, (Buf_Type)buf, len); + } + memmove(cb->recv_buffer + idx, data, len); + t = t->next; } - if (cur != buffer_size) { - printf("11122 cur[%d] cb->cur_total_len:[%d] \n", cur, cb->total_len); - exit(11122); + } + { + // fec 解码成功 开始恢复 + Ptr_Node *t = cb->decode_origin_list->head; + while (t) { + Data_Frame_Type *d = (Data_Frame_Type *)t->ptr; + fec_decode(d->data, d->size, 1, cb->dec); + t = t->next; } - cb->next_recv((Base_CB*)cb, total, cb->total_len, user); - g_free(total); - cb->whole_packet_success.update(true); - } else { // 需要恢复 - if (rn + rk >= n) { // 具备恢复条件 - cb->recv_buffer = (Buf_Type)g_malloc(buffer_size); - cb->idx_array = (bool*)g_malloc(n); - for (IUINT16 i = 0; i < n; i++) { - cb->idx_array[i] = false; - } - { - // 添加原始数据 - Ptr_Node* t = cb->decode_origin_list->head; - while (t) { - Data_Frame_Type* d = (Data_Frame_Type*)t->ptr; - cb->idx_array[d->i] = true; - Len_Type len = d->size - fec_header_len; - char* data = d->data + fec_header_len; - PSC_ASSERT(len == s, ""); - PSC_ASSERT(d->i < n, ""); - IUINT16 idx = d->i * s; - PSC_ASSERT(idx + len <= buffer_size, ""); - if (recv_debug) { - printf("origin_writer idx:%u[%u,%u] \r\n", d->i, idx, len); - // push_mem(cb->recv_data_list, (Buf_Type)buf, len); - } - memmove(cb->recv_buffer + idx, data, len); - t = t->next; - } - } - { - // fec 解码成功 开始恢复 - Ptr_Node* t = cb->decode_origin_list->head; - while (t) { - Data_Frame_Type* d = (Data_Frame_Type*)t->ptr; - fec_decode(d->data, d->size, 1, cb->dec); - t = t->next; - } - t = cb->decode_cache_list->head; - while (t) { - Data_Frame_Type* d = (Data_Frame_Type*)t->ptr; - fec_decode(d->data, d->size, 1, cb->dec); - t = t->next; - } - flush_fec_decoder(cb->dec); - } - bool ok = true; - for (IUINT16 i = 0; i < cb->n; i++) { - if (cb->idx_array[i] == false) { - ok = false; - break; - } - } - if (ok) { - if (recv_debug) { - printf("恢复成功 原始帧数%d 恢复帧数%d n%d \n", rn, rk, n); - print_dec_state(cb); - } -#ifdef Packet_0_9_check_enable - int failed_pos = check_cycle_0_9(cb->recv_buffer, cb->cur_total_len - 1); - if (failed_pos != 0) { - printf("恢复成功检查失败 失败为位置[%d, %d]\r\n", failed_pos, cb->cur_total_len); - exit(111111); - } -#endif - cb->next_recv((Base_CB*)cb, cb->recv_buffer, cb->total_len, user); - cb->whole_packet_success.update(true); - cb->decode_packet_success.update(true); - } else { - // 恢复失败 - if (recv_debug) { - printf("恢复失败 原始帧数%d 恢复帧数%d \n", rn, rk); - } - cb->whole_packet_success.update(false); - cb->decode_packet_success.update(false); - // recv_all_origin_packet(cb, user); - } - g_free(cb->recv_buffer); - g_free(cb->idx_array); - cb->recv_buffer = NULL; - cb->idx_array = NULL; - } else { - if (recv_debug) { - printf("不具备恢复条件 原始帧数%d 恢复帧数%d \n", rn, rk); - } - cb->whole_packet_success.update(false); - - // recv_all_origin_packet(cb, user); + t = cb->decode_cache_list->head; + while (t) { + Data_Frame_Type *d = (Data_Frame_Type *)t->ptr; + fec_decode(d->data, d->size, 1, cb->dec); + t = t->next; } - } - // 解码完成清理状态 - Ptr_List_pop_all(cb->decode_origin_list); - Ptr_List_pop_all(cb->decode_cache_list); - delete_fec_decoder(cb->dec); - cb->dec = new_fec_decoder(cb, decode_writer); - - - -} - -void UDP_FEC_CB::recv(Buf_Type buf, Len_Type len, void* user) { - UDP_FEC_Base_Packet* bp = (UDP_FEC_Base_Packet*)buf; - if (bp->type == UDP_FEC_Channel_State) { - // 接收到对方的 通道状态 调整发送包的配置参数 - UDP_FEC_Packet_state* state = (UDP_FEC_Packet_state*)buf; - printf("接收到对方状态包 调整自身fec参数\r\n"); - printf("码率 %d ‰ \r\n", state->code_rate); - printf("单包接收成功率 %d ‰ \r\n", state->single_packet_success); - printf("整体包接收成功率 %d ‰ \r\n", state->whole_packet_success); - printf(" fec解码成功率 %d ‰ \r\n", state->decode_packet_success); - double rate = 0.8 * state->single_packet_success/1000.0; - if (rate == 0) { - return; + flush_fec_decoder(cb->dec); + } + bool ok = true; + for (IUINT16 i = 0; i < cb->n; i++) { + if (cb->idx_array[i] == false) { + ok = false; + break; } - redundancy = 1.0 - rate; - } else if (bp->type == UDP_FEC_CB_Data_Packet) { - // 对端发来数据包 - UDP_FEC_Packet* packet = (UDP_FEC_Packet*)buf; - IUINT32 seq = packet->header.seq; - UDP_FEC_Packet_Header* ph = (UDP_FEC_Packet_Header*)buf; - Fec_Header* h = (Fec_Header*)(buf + fec_packet_header_len); - long v = _itimediff(seq, last_seq); - - if (v < 0) { - // 首个包 或者序号错乱直接丢弃 - last_seq = seq; - if (init == false) { - // 首个包 - } else { - return; - } - } - - - if (v > 1) { - IINT32 up = (v-1) * (n + k); // 失败次数 - single_packet_success.update(-up); - } - // v==1 正常更替序号 v>1 丢包 - if (v >= 1) { - if (init == true) { - flush_recv_decode(this, user); - last_seq = seq; - init = false; - n = 0; - k = 0; - s = 0; - total_len = 0; - } - } - - - - if (init == false) { - total_len = ph->total_len; - n = h->n; - k = (h->kwg) & ((1 << KBITS) - 1); - s = len - fec_packet_header_len - fec_header_len; - init = true; - } - Len_Type i, n; - i = h->i; - n = h->n; - - PSC_ASSERT(i < n + k, ""); - PSC_ASSERT_EQ(k, (h->kwg) & ((1 << KBITS) - 1)); - PSC_ASSERT_EQ(s, len - fec_packet_header_len - fec_header_len); - - printf("snk [%d, %d, %d] \r\n", s, n, k); - // IUINT16 k = (h->kwg) & ((1 << KBITS) - 1); - // IUINT16 w = ( (h->kwg) >> KBITS) & ((1 << WBITS) - 1); - // IUINT16 g = (h->kwg) >> (KBITS + WBITS); - char origin_packet = i < n ? 1 : 0; // 是否是原始数据帧 + } + if (ok) { if (recv_debug) { - printf("[enter] [%d,%d] origin:%d cache_size:%d ", seq, i, origin_packet, - decode_origin_list->len); + printf("恢复成功 原始帧数%d 恢复帧数%d n%d \n", rn, rk, n); + print_dec_state(cb); } - // 448 + 16 = 464 - if (origin_packet) { - // if (recv_debug) printf("[cache] [%d,%d] recover:%d\n", packet_id, fh_i, cb->decode_need_recover); - if (recv_debug) printf("[origin cache] \n"); - Data_Frame_Type* d = Data_Frame_Type_create(seq, i, n, k, s, buf + fec_packet_header_len, - len - fec_packet_header_len); - Ptr_List_append(decode_origin_list, d); #ifdef Packet_0_9_check_enable - if (fh_i != cb->cur_n - 1) { - int it = check_cycle_0_9(buf + fec_packet_header_len + fec_header_len, - len - fec_packet_header_len - fec_header_len); - if (it != 0) { - printf("origin_packet check_cycle_0_9 error i:[%d] error pos[%d] \r\n", fh_i, it); - exit(12222); - } - } -#endif - // push_mem(cb->decode_origin_list, (Buf_Type)(buf + header_len), len - header_len); - } else { - if (decode_origin_list->len == n) { - // 原始帧收齐 无需恢复帧 - if (recv_debug) printf("[recover skip] \n"); - } else { - if (recv_debug) printf("[recover recv] \n"); - Data_Frame_Type* d = Data_Frame_Type_create(seq, i, n, k, s, buf + fec_packet_header_len, - len - fec_packet_header_len); - Ptr_List_append(decode_cache_list, d); - // push_mem(cb->decode_cache_list, (Buf_Type)(buf + header_len), len - header_len); - } + int failed_pos = + check_cycle_0_9(cb->recv_buffer, cb->cur_total_len - 1); + if (failed_pos != 0) { + printf("恢复成功检查失败 失败为位置[%d, %d]\r\n", failed_pos, + cb->cur_total_len); + exit(111111); } +#endif + cb->next_recv((Base_CB *)cb, cb->recv_buffer, cb->total_len, user); + cb->whole_packet_success.update(true); + cb->decode_packet_success.update(true); + } else { + // 恢复失败 + if (recv_debug) { + printf("恢复失败 原始帧数%d 恢复帧数%d \n", rn, rk); + } + cb->whole_packet_success.update(false); + cb->decode_packet_success.update(false); + // recv_all_origin_packet(cb, user); + } + g_free(cb->recv_buffer); + g_free(cb->idx_array); + cb->recv_buffer = NULL; + cb->idx_array = NULL; + } else { + if (recv_debug) { + printf("不具备恢复条件 原始帧数%d 恢复帧数%d \n", rn, rk); + } + cb->whole_packet_success.update(false); + + // recv_all_origin_packet(cb, user); } + } + // 解码完成清理状态 + Ptr_List_pop_all(cb->decode_origin_list); + Ptr_List_pop_all(cb->decode_cache_list); + delete_fec_decoder(cb->dec); + cb->dec = new_fec_decoder(cb, decode_writer); } + +void UDP_FEC_CB::recv(Buf_Type buf, Len_Type len, void *user) { + UDP_FEC_Base_Packet *bp = (UDP_FEC_Base_Packet *)buf; + if (bp->type == UDP_FEC_Channel_State) { + // 接收到对方的 通道状态 调整发送包的配置参数 + UDP_FEC_Packet_state *state = (UDP_FEC_Packet_state *)buf; + printf("接收到对方状态包 调整自身fec参数\r\n"); + printf("码率 %d ‰ \r\n", state->code_rate); + printf("单包接收成功率 %d ‰ \r\n", state->single_packet_success); + printf("整体包接收成功率 %d ‰ \r\n", state->whole_packet_success); + printf(" fec解码成功率 %d ‰ \r\n", state->decode_packet_success); + double rate = 0.8 * state->single_packet_success / 1000.0; + if (rate == 0) { + return; + } + redundancy = 1.0 - rate; + } else if (bp->type == UDP_FEC_CB_Data_Packet) { + // 对端发来数据包 + UDP_FEC_Packet *packet = (UDP_FEC_Packet *)buf; + IUINT32 seq = packet->header.seq; + UDP_FEC_Packet_Header *ph = (UDP_FEC_Packet_Header *)buf; + Fec_Header *h = (Fec_Header *)(buf + fec_packet_header_len); + long v = _itimediff(seq, last_seq); + + if (v < 0) { + // 首个包 或者序号错乱直接丢弃 + last_seq = seq; + if (init == false) { + // 首个包 + } else { + return; + } + } + + if (v > 1) { + IINT32 up = (v - 1) * (n + k); // 失败次数 + single_packet_success.update(-up); + } + // v==1 正常更替序号 v>1 丢包 + if (v >= 1) { + if (init == true) { + flush_recv_decode(this, user); + last_seq = seq; + init = false; + n = 0; + k = 0; + s = 0; + total_len = 0; + } + } + + if (init == false) { + total_len = ph->total_len; + n = h->n; + k = (h->kwg) & ((1 << KBITS) - 1); + s = len - fec_packet_header_len - fec_header_len; + init = true; + } + Len_Type i, n; + i = h->i; + n = h->n; + + PSC_ASSERT(i < n + k, ""); + PSC_ASSERT_EQ(k, (h->kwg) & ((1 << KBITS) - 1)); + PSC_ASSERT_EQ(s, len - fec_packet_header_len - fec_header_len); + + printf("snk [%d, %d, %d] \r\n", s, n, k); + // IUINT16 k = (h->kwg) & ((1 << KBITS) - 1); + // IUINT16 w = ( (h->kwg) >> KBITS) & ((1 << WBITS) - 1); + // IUINT16 g = (h->kwg) >> (KBITS + WBITS); + char origin_packet = i < n ? 1 : 0; // 是否是原始数据帧 + if (recv_debug) { + printf("[enter] [%d,%d] origin:%d cache_size:%d ", seq, i, + origin_packet, decode_origin_list->len); + } + // 448 + 16 = 464 + if (origin_packet) { + // if (recv_debug) printf("[cache] [%d,%d] recover:%d\n", packet_id, + // fh_i, cb->decode_need_recover); + if (recv_debug) + printf("[origin cache] \n"); + Data_Frame_Type *d = + Data_Frame_Type_create(seq, i, n, k, s, buf + fec_packet_header_len, + len - fec_packet_header_len); + Ptr_List_append(decode_origin_list, d); +#ifdef Packet_0_9_check_enable + if (fh_i != cb->cur_n - 1) { + int it = check_cycle_0_9(buf + fec_packet_header_len + fec_header_len, + len - fec_packet_header_len - fec_header_len); + if (it != 0) { + printf( + "origin_packet check_cycle_0_9 error i:[%d] error pos[%d] \r\n", + fh_i, it); + exit(12222); + } + } +#endif + // push_mem(cb->decode_origin_list, (Buf_Type)(buf + header_len), len - + // header_len); + } else { + if (decode_origin_list->len == n) { + // 原始帧收齐 无需恢复帧 + if (recv_debug) + printf("[recover skip] \n"); + } else { + if (recv_debug) + printf("[recover recv] \n"); + Data_Frame_Type *d = + Data_Frame_Type_create(seq, i, n, k, s, buf + fec_packet_header_len, + len - fec_packet_header_len); + Ptr_List_append(decode_cache_list, d); + // push_mem(cb->decode_cache_list, (Buf_Type)(buf + header_len), len - + // header_len); + } + } + } } +} // namespace Psc diff --git a/Core/transmit_protocol/udp_fec_s/udp_fec_send.cpp b/Core/transmit_protocol/udp_fec_s/udp_fec_send.cpp index bb3c8ac..f918709 100644 --- a/Core/transmit_protocol/udp_fec_s/udp_fec_send.cpp +++ b/Core/transmit_protocol/udp_fec_s/udp_fec_send.cpp @@ -5,119 +5,123 @@ #include #include namespace Psc { -size_t encode_writer(fec_encoder* e, void* buf, size_t size, size_t count, void* userData) { - UDP_FEC_CB* cb = (UDP_FEC_CB*)userData; - // - // printf("encode %d \r\n", size); - // headerType* fh = (headerType*)((char*)buf); - push_mem(cb->send_data_list, (Buf_Type)buf, size); - if (count != 1) { - printf("encode_writer not one %llu \n", size); +size_t encode_writer(fec_encoder *e, void *buf, size_t size, size_t count, + void *userData) { + UDP_FEC_CB *cb = (UDP_FEC_CB *)userData; + // + // printf("encode %d \r\n", size); + // headerType* fh = (headerType*)((char*)buf); + push_mem(cb->send_data_list, (Buf_Type)buf, size); + if (count != 1) { + printf("encode_writer not one %llu \n", size); #ifndef USE_Embedded_C - exit(-20); + exit(-20); #endif - } - return 0; + } + return 0; } -void calc_snk(Len_Type total_len, double redundancy, IUINT16* s, IUINT16* n, IUINT16* k, IUINT16* last_s); +void calc_snk(Len_Type total_len, double redundancy, IUINT16 *s, IUINT16 *n, + IUINT16 *k, IUINT16 *last_s); -void UDP_FEC_CB::send(Buf_Type total_buf, Len_Type total_len, void* user) { - IUINT32 current = get_millisecond(); - IUINT32 diff = _itimediff(current, send_state_time_last_time); - if (diff > send_state_time_millisecond_interval) { - UDP_FEC_Packet_state_send(this); - send_state_time_last_time = current; - } +void UDP_FEC_CB::send(Buf_Type total_buf, Len_Type total_len, void *user) { + IUINT32 current = get_millisecond(); + IUINT32 diff = _itimediff(current, send_state_time_last_time); + if (diff > send_state_time_millisecond_interval) { + UDP_FEC_Packet_state_send(this); + send_state_time_last_time = current; + } - IUINT16 s, n, k, last_s; - calc_snk(total_len, redundancy, &s, &n, &k, &last_s); - int w = 8; - int g = 4; - int b = 0; - char* errmsg = NULL; - fec_encoder* enc = new_fec_encoder(this, encode_writer, &errmsg, s, n, k, w, g, b); - char* data = (Buf_Type)g_malloc(s); - for (IUINT16 i = 0; i < n; i++) { - Buf_Type buf = total_buf + i * s; - if (i != n - 1) { - fec_encode((fecPayload*)buf, enc); - } else { - memmove(data, buf, last_s); - fec_encode((fecPayload*)data, enc); - } + IUINT16 s, n, k, last_s; + calc_snk(total_len, redundancy, &s, &n, &k, &last_s); + int w = 8; + int g = 4; + int b = 0; + char *errmsg = NULL; + fec_encoder *enc = + new_fec_encoder(this, encode_writer, &errmsg, s, n, k, w, g, b); + char *data = (Buf_Type)g_malloc(s); + for (IUINT16 i = 0; i < n; i++) { + Buf_Type buf = total_buf + i * s; + if (i != n - 1) { + fec_encode((fecPayload *)buf, enc); + } else { + memmove(data, buf, last_s); + fec_encode((fecPayload *)data, enc); } - g_free(data); - UDP_FEC_Packet_Header header; - header.seq = send_seq; - header.total_len = total_len; - header.type = UDP_FEC_CB_Data_Packet; - ND* t = send_data_list->head; - size_t send_size = fec_packet_header_len + t->len; - char* send_data = (Buf_Type)g_malloc(send_size); - while (t) { - memcpy(send_data, &header, fec_packet_header_len); - memcpy(send_data + fec_packet_header_len, t->buf, t->len); - // Fec_Header* h = (Fec_Header*)send_data; - // h->n; - // IUINT16 k = (h->kwg) & ((1 << KBITS) - 1); - // IUINT16 w = ( (h->kwg) >> KBITS) & ((1 << WBITS) - 1); - // IUINT16 g = (h->kwg) >> (KBITS + WBITS); - // send_data += t->size; - next_send(this, send_data, send_size, user); - t = t->next; - } - // cb->next_send((Base_CB*)cb, total, size, user); - clear_all_node(send_data_list); - g_free(send_data); - delete_fec_encoder(enc); - send_seq++; + } + g_free(data); + UDP_FEC_Packet_Header header; + header.seq = send_seq; + header.total_len = total_len; + header.type = UDP_FEC_CB_Data_Packet; + ND *t = send_data_list->head; + size_t send_size = fec_packet_header_len + t->len; + char *send_data = (Buf_Type)g_malloc(send_size); + while (t) { + memcpy(send_data, &header, fec_packet_header_len); + memcpy(send_data + fec_packet_header_len, t->buf, t->len); + // Fec_Header* h = (Fec_Header*)send_data; + // h->n; + // IUINT16 k = (h->kwg) & ((1 << KBITS) - 1); + // IUINT16 w = ( (h->kwg) >> KBITS) & ((1 << WBITS) - 1); + // IUINT16 g = (h->kwg) >> (KBITS + WBITS); + // send_data += t->size; + next_send(this, send_data, send_size, user); + t = t->next; + } + // cb->next_send((Base_CB*)cb, total, size, user); + clear_all_node(send_data_list); + g_free(send_data); + delete_fec_encoder(enc); + send_seq++; } +void calc_snk(Len_Type total_len, double redundancy, IUINT16 *s, IUINT16 *n, + IUINT16 *k, IUINT16 *last_s) { + // 先估算原始分片数量 + int n_est = (int)(std::sqrt((float)total_len) / 10); + if (n_est < 1) + n_est = 1; + // 按冗余度算出 k + *k = (IUINT16)(n_est * redundancy / (1.0 - redundancy) + 0.5); + if (*k < 1) + *k = 1; + // 计算基础分片大小 + int raw_s = (total_len + n_est - 1) / n_est; // 向上取整,保证能覆盖 + *s = (raw_s + 15) & ~15; // 向上取整到16的倍数 + // 根据片大小反算分片数 + *n = (total_len + *s - 1) / *s; + // 最后一片大小 + *last_s = total_len - (*s) * ((*n) - 1); + if (*last_s <= 0) + *last_s = *s; // 边界情况 + // ====== 内部断言校验 ====== + int original_cover = (*s) * ((*n) - 1) + (*last_s); + // 1. 覆盖长度必须刚好等于 total_len + PSC_ASSERT(original_cover == total_len, ""); + // 2. last_s 必须在 (0, s] 内 + PSC_ASSERT(*last_s > 0 && *last_s <= *s, ""); + // 3. 至少要有 1 个分片 + PSC_ASSERT(*n >= 1, ""); + // 4. 至少要有 1 个冗余 + PSC_ASSERT(*k >= 1, ""); - - -void calc_snk(Len_Type total_len, double redundancy, IUINT16* s, IUINT16* n, IUINT16* k, IUINT16* last_s) { - // 先估算原始分片数量 - int n_est = (int)(std::sqrt((float)total_len) / 10); - if (n_est < 1) n_est = 1; - // 按冗余度算出 k - *k = (IUINT16)(n_est * redundancy / (1.0 - redundancy) + 0.5); - if (*k < 1) *k = 1; - // 计算基础分片大小 - int raw_s = (total_len + n_est - 1) / n_est; // 向上取整,保证能覆盖 - *s = (raw_s + 15) & ~15; // 向上取整到16的倍数 - // 根据片大小反算分片数 - *n = (total_len + *s - 1) / *s; - // 最后一片大小 - *last_s = total_len - (*s) * ((*n) - 1); - if (*last_s <= 0) *last_s = *s; // 边界情况 - // ====== 内部断言校验 ====== - int original_cover = (*s) * ((*n) - 1) + (*last_s); - // 1. 覆盖长度必须刚好等于 total_len - PSC_ASSERT(original_cover == total_len, ""); - // 2. last_s 必须在 (0, s] 内 - PSC_ASSERT(*last_s > 0 && *last_s <= *s, ""); - // 3. 至少要有 1 个分片 - PSC_ASSERT(*n >= 1, ""); - // 4. 至少要有 1 个冗余 - PSC_ASSERT(*k >= 1, ""); - - PSC_ASSERT(*n + *k <= 255, ""); + PSC_ASSERT(*n + *k <= 255, ""); } - void test_calc_snk_all() { - IUINT16 s, n, k, l; - srand((unsigned)time(NULL)); // 初始化随机数种子 - for (int i = 0; i < 1000; i++) { - // total_len 在 [1, 100000] 范围 - Len_Type total_len = 1 + rand() % 2000; - // 冗余度在 (0.05, 0.95) 范围,避免 0 或 1 - double redundancy = 0.05 + (rand() % 91) / 100.0; - calc_snk(total_len, redundancy, &s, &n, &k, &l); - // 如果你想看到测试进度,可以加打印 - printf("[%d] total_len=%d redundancy=%.3f -> n=%u k=%u s=%u l=%u\n", i, total_len, redundancy, n, k, s, l); - } - printf("✅ 1000 组随机 calc_snk 测试完成\n"); + IUINT16 s, n, k, l; + srand((unsigned)time(NULL)); // 初始化随机数种子 + for (int i = 0; i < 1000; i++) { + // total_len 在 [1, 100000] 范围 + Len_Type total_len = 1 + rand() % 2000; + // 冗余度在 (0.05, 0.95) 范围,避免 0 或 1 + double redundancy = 0.05 + (rand() % 91) / 100.0; + calc_snk(total_len, redundancy, &s, &n, &k, &l); + // 如果你想看到测试进度,可以加打印 + printf("[%d] total_len=%d redundancy=%.3f -> n=%u k=%u s=%u l=%u\n", i, + total_len, redundancy, n, k, s, l); + } + printf("✅ 1000 组随机 calc_snk 测试完成\n"); } } \ No newline at end of file diff --git a/Core/transmit_protocol/uthash/utarray.h b/Core/transmit_protocol/uthash/utarray.h index 6509ff9..a004933 100644 --- a/Core/transmit_protocol/uthash/utarray.h +++ b/Core/transmit_protocol/uthash/utarray.h @@ -27,11 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define UTARRAY_H #define UTARRAY_VERSION 2.3.0 +#include "../global.h" #include /* size_t */ #include /* exit */ #include /* memset, etc */ -#include "../global.h" - #ifdef __GNUC__ #define UTARRAY_UNUSED __attribute__((__unused__)) @@ -43,203 +42,253 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define utarray_oom() exit(-1) #endif -typedef void (ctor_f)(void *dst, const void *src); -typedef void (dtor_f)(void *elt); -typedef void (init_f)(void *elt); +typedef void(ctor_f)(void *dst, const void *src); +typedef void(dtor_f)(void *elt); +typedef void(init_f)(void *elt); typedef struct { - size_t sz; - init_f *init; - ctor_f *copy; - dtor_f *dtor; + size_t sz; + init_f *init; + ctor_f *copy; + dtor_f *dtor; } UT_icd; typedef struct { - unsigned i,n;/* i: index of next available slot, n: num slots */ - UT_icd icd; /* initializer, copy and destructor functions */ - char *d; /* n slots of size icd->sz*/ + unsigned i, n; /* i: index of next available slot, n: num slots */ + UT_icd icd; /* initializer, copy and destructor functions */ + char *d; /* n slots of size icd->sz*/ } UT_array; -#define utarray_init(a,_icd) do { \ - memset(a,0,sizeof(UT_array)); \ - (a)->icd = *(_icd); \ -} while(0) +#define utarray_init(a, _icd) \ + do { \ + memset(a, 0, sizeof(UT_array)); \ + (a)->icd = *(_icd); \ + } while (0) -#define utarray_done(a) do { \ - if ((a)->n) { \ - if ((a)->icd.dtor) { \ - unsigned _ut_i; \ - for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr(a,_ut_i)); \ - } \ - } \ - g_free((a)->d); \ - } \ - (a)->n=0; \ -} while(0) +#define utarray_done(a) \ + do { \ + if ((a)->n) { \ + if ((a)->icd.dtor) { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a, _ut_i)); \ + } \ + } \ + g_free((a)->d); \ + } \ + (a)->n = 0; \ + } while (0) -#define utarray_new(a,_icd) do { \ - (a) = (UT_array*)g_malloc(sizeof(UT_array)); \ - if ((a) == NULL) { \ - utarray_oom(); \ - } \ - utarray_init(a,_icd); \ -} while(0) +#define utarray_new(a, _icd) \ + do { \ + (a) = (UT_array *)g_malloc(sizeof(UT_array)); \ + if ((a) == NULL) { \ + utarray_oom(); \ + } \ + utarray_init(a, _icd); \ + } while (0) -#define utarray_free(a) do { \ - utarray_done(a); \ - g_free(a); \ -} while(0) +#define utarray_free(a) \ + do { \ + utarray_done(a); \ + g_free(a); \ + } while (0) -#define utarray_reserve(a,by) do { \ - if (((a)->i+(by)) > (a)->n) { \ - char *utarray_tmp; \ - while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \ - utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \ - if (utarray_tmp == NULL) { \ - utarray_oom(); \ - } \ - (a)->d=utarray_tmp; \ - } \ -} while(0) +#define utarray_reserve(a, by) \ + do { \ + if (((a)->i + (by)) > (a)->n) { \ + char *utarray_tmp; \ + while (((a)->i + (by)) > (a)->n) { \ + (a)->n = ((a)->n ? (2 * (a)->n) : 8); \ + } \ + utarray_tmp = (char *)realloc((a)->d, (a)->n * (a)->icd.sz); \ + if (utarray_tmp == NULL) { \ + utarray_oom(); \ + } \ + (a)->d = utarray_tmp; \ + } \ + } while (0) -#define utarray_push_back(a,p) do { \ - utarray_reserve(a,1); \ - if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \ - else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \ -} while(0) +#define utarray_push_back(a, p) \ + do { \ + utarray_reserve(a, 1); \ + if ((a)->icd.copy) { \ + (a)->icd.copy(_utarray_eltptr(a, (a)->i++), p); \ + } else { \ + memcpy(_utarray_eltptr(a, (a)->i++), p, (a)->icd.sz); \ + }; \ + } while (0) -#define utarray_pop_back(a) do { \ - if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \ - else { (a)->i--; } \ -} while(0) +#define utarray_pop_back(a) \ + do { \ + if ((a)->icd.dtor) { \ + (a)->icd.dtor(_utarray_eltptr(a, --((a)->i))); \ + } else { \ + (a)->i--; \ + } \ + } while (0) -#define utarray_extend_back(a) do { \ - utarray_reserve(a,1); \ - if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \ - else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \ - (a)->i++; \ -} while(0) +#define utarray_extend_back(a) \ + do { \ + utarray_reserve(a, 1); \ + if ((a)->icd.init) { \ + (a)->icd.init(_utarray_eltptr(a, (a)->i)); \ + } else { \ + memset(_utarray_eltptr(a, (a)->i), 0, (a)->icd.sz); \ + } \ + (a)->i++; \ + } while (0) #define utarray_len(a) ((a)->i) -#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL) -#define _utarray_eltptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j)))) +#define utarray_eltptr(a, j) (((j) < (a)->i) ? _utarray_eltptr(a, j) : NULL) +#define _utarray_eltptr(a, j) ((void *)((a)->d + ((a)->icd.sz * (j)))) -#define utarray_insert(a,p,j) do { \ - if ((j) > (a)->i) utarray_resize(a,j); \ - utarray_reserve(a,1); \ - if ((j) < (a)->i) { \ - memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \ - ((a)->i - (j))*((a)->icd.sz)); \ - } \ - if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \ - else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \ - (a)->i++; \ -} while(0) +#define utarray_insert(a, p, j) \ + do { \ + if ((j) > (a)->i) \ + utarray_resize(a, j); \ + utarray_reserve(a, 1); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a, (j) + 1), _utarray_eltptr(a, j), \ + ((a)->i - (j)) * ((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { \ + (a)->icd.copy(_utarray_eltptr(a, j), p); \ + } else { \ + memcpy(_utarray_eltptr(a, j), p, (a)->icd.sz); \ + }; \ + (a)->i++; \ + } while (0) -#define utarray_replace(a,p,j) do { \ - if ((a)->icd.dtor) { (a)->icd.dtor(_utarray_eltptr(a,j)); } \ - if ((a)->icd.copy) { (a)->icd.copy(_utarray_eltptr(a,j), p); } \ - else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); } \ -} while(0) +#define utarray_replace(a, p, j) \ + do { \ + if ((a)->icd.dtor) { \ + (a)->icd.dtor(_utarray_eltptr(a, j)); \ + } \ + if ((a)->icd.copy) { \ + (a)->icd.copy(_utarray_eltptr(a, j), p); \ + } else { \ + memcpy(_utarray_eltptr(a, j), p, (a)->icd.sz); \ + } \ + } while (0) -#define utarray_inserta(a,w,j) do { \ - if (utarray_len(w) == 0) break; \ - if ((j) > (a)->i) utarray_resize(a,j); \ - utarray_reserve(a,utarray_len(w)); \ - if ((j) < (a)->i) { \ - memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \ - _utarray_eltptr(a,j), \ - ((a)->i - (j))*((a)->icd.sz)); \ - } \ - if ((a)->icd.copy) { \ - unsigned _ut_i; \ - for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \ - (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \ - } \ - } else { \ - memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \ - utarray_len(w)*((a)->icd.sz)); \ - } \ - (a)->i += utarray_len(w); \ -} while(0) +#define utarray_inserta(a, w, j) \ + do { \ + if (utarray_len(w) == 0) \ + break; \ + if ((j) > (a)->i) \ + utarray_resize(a, j); \ + utarray_reserve(a, utarray_len(w)); \ + if ((j) < (a)->i) { \ + memmove(_utarray_eltptr(a, (j) + utarray_len(w)), _utarray_eltptr(a, j), \ + ((a)->i - (j)) * ((a)->icd.sz)); \ + } \ + if ((a)->icd.copy) { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (w)->i; _ut_i++) { \ + (a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), \ + _utarray_eltptr(w, _ut_i)); \ + } \ + } else { \ + memcpy(_utarray_eltptr(a, j), _utarray_eltptr(w, 0), \ + utarray_len(w) * ((a)->icd.sz)); \ + } \ + (a)->i += utarray_len(w); \ + } while (0) -#define utarray_resize(dst,num) do { \ - unsigned _ut_i; \ - if ((dst)->i > (unsigned)(num)) { \ - if ((dst)->icd.dtor) { \ - for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \ - (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \ - } \ - } \ - } else if ((dst)->i < (unsigned)(num)) { \ - utarray_reserve(dst, (num) - (dst)->i); \ - if ((dst)->icd.init) { \ - for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \ - (dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \ - } \ - } else { \ - memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \ - } \ - } \ - (dst)->i = (num); \ -} while(0) +#define utarray_resize(dst, num) \ + do { \ + unsigned _ut_i; \ + if ((dst)->i > (unsigned)(num)) { \ + if ((dst)->icd.dtor) { \ + for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \ + (dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \ + } \ + } \ + } else if ((dst)->i < (unsigned)(num)) { \ + utarray_reserve(dst, (num) - (dst)->i); \ + if ((dst)->icd.init) { \ + for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \ + (dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \ + } \ + } else { \ + memset(_utarray_eltptr(dst, (dst)->i), 0, \ + (dst)->icd.sz * ((num) - (dst)->i)); \ + } \ + } \ + (dst)->i = (num); \ + } while (0) -#define utarray_concat(dst,src) do { \ - utarray_inserta(dst, src, utarray_len(dst)); \ -} while(0) +#define utarray_concat(dst, src) \ + do { \ + utarray_inserta(dst, src, utarray_len(dst)); \ + } while (0) -#define utarray_erase(a,pos,len) do { \ - if ((a)->icd.dtor) { \ - unsigned _ut_i; \ - for (_ut_i = 0; _ut_i < (len); _ut_i++) { \ - (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \ - } \ - } \ - if ((a)->i > ((pos) + (len))) { \ - memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \ - ((a)->i - ((pos) + (len))) * (a)->icd.sz); \ - } \ - (a)->i -= (len); \ -} while(0) +#define utarray_erase(a, pos, len) \ + do { \ + if ((a)->icd.dtor) { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (len); _ut_i++) { \ + (a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \ + } \ + } \ + if ((a)->i > ((pos) + (len))) { \ + memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \ + ((a)->i - ((pos) + (len))) * (a)->icd.sz); \ + } \ + (a)->i -= (len); \ + } while (0) -#define utarray_renew(a,u) do { \ - if (a) utarray_clear(a); \ - else utarray_new(a, u); \ -} while(0) +#define utarray_renew(a, u) \ + do { \ + if (a) \ + utarray_clear(a); \ + else \ + utarray_new(a, u); \ + } while (0) -#define utarray_clear(a) do { \ - if ((a)->i > 0) { \ - if ((a)->icd.dtor) { \ - unsigned _ut_i; \ - for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \ - (a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \ - } \ - } \ - (a)->i = 0; \ - } \ -} while(0) +#define utarray_clear(a) \ + do { \ + if ((a)->i > 0) { \ + if ((a)->icd.dtor) { \ + unsigned _ut_i; \ + for (_ut_i = 0; _ut_i < (a)->i; _ut_i++) { \ + (a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \ + } \ + } \ + (a)->i = 0; \ + } \ + } while (0) -#define utarray_sort(a,cmp) do { \ - qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ -} while(0) +#define utarray_sort(a, cmp) \ + do { \ + qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \ + } while (0) -#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp) +#define utarray_find(a, v, cmp) bsearch((v), (a)->d, (a)->i, (a)->icd.sz, cmp) -#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL) -#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : (((a)->i != utarray_eltidx(a,e)+1) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL)) -#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) != 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL)) -#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL) -#define utarray_eltidx(a,e) (((char*)(e) - (a)->d) / (a)->icd.sz) +#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a, 0)) : NULL) +#define utarray_next(a, e) \ + (((e) == NULL) ? utarray_front(a) \ + : (((a)->i != utarray_eltidx(a, e) + 1) \ + ? _utarray_eltptr(a, utarray_eltidx(a, e) + 1) \ + : NULL)) +#define utarray_prev(a, e) \ + (((e) == NULL) ? utarray_back(a) \ + : ((utarray_eltidx(a, e) != 0) \ + ? _utarray_eltptr(a, utarray_eltidx(a, e) - 1) \ + : NULL)) +#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a, (a)->i - 1)) : NULL) +#define utarray_eltidx(a, e) (((char *)(e) - (a)->d) / (a)->icd.sz) /* last we pre-define a few icd for common utarrays of ints and strings */ static void utarray_str_cpy(void *dst, const void *src) { char *const *srcc = (char *const *)src; - char **dstc = (char**)dst; + char **dstc = (char **)dst; if (*srcc == NULL) { *dstc = NULL; } else { - *dstc = (char*)g_malloc(strlen(*srcc) + 1); + *dstc = (char *)g_malloc(strlen(*srcc) + 1); if (*dstc == NULL) { utarray_oom(); } else { @@ -248,12 +297,14 @@ static void utarray_str_cpy(void *dst, const void *src) { } } static void utarray_str_dtor(void *elt) { - char **eltc = (char**)elt; - if (*eltc != NULL) g_free(*eltc); + char **eltc = (char **)elt; + if (*eltc != NULL) + g_free(*eltc); } -static const UT_icd ut_str_icd UTARRAY_UNUSED = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor}; -static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int),NULL,NULL,NULL}; -static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void*),NULL,NULL,NULL}; - +static const UT_icd ut_str_icd UTARRAY_UNUSED = { + sizeof(char *), NULL, utarray_str_cpy, utarray_str_dtor}; +static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int), NULL, NULL, NULL}; +static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void *), NULL, NULL, + NULL}; #endif /* UTARRAY_H */ diff --git a/Core/transmit_protocol/uthash/uthash.h b/Core/transmit_protocol/uthash/uthash.h index 6c78367..7176bce 100644 --- a/Core/transmit_protocol/uthash/uthash.h +++ b/Core/transmit_protocol/uthash/uthash.h @@ -26,15 +26,15 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define UTHASH_VERSION 2.3.0 -#include /* memcmp, memset, strlen */ -#include /* ptrdiff_t */ -#include /* exit */ +#include /* ptrdiff_t */ +#include /* exit */ +#include /* memcmp, memset, strlen */ #if defined(HASH_NO_STDINT) && HASH_NO_STDINT /* The user doesn't have , and must figure out their own way to provide definitions for uint8_t and uint32_t. */ #else -#include /* uint8_t, uint32_t */ +#include /* uint8_t, uint32_t */ #endif /* These macros use decltype or the earlier __typeof GNU extension. @@ -42,61 +42,62 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. when compiling c++ source) this code uses whatever method is needed or, for VS2008 where neither is available, uses casting workarounds. */ #if !defined(DECLTYPE) && !defined(NO_DECLTYPE) -#if defined(_MSC_VER) /* MS compiler */ -#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #define DECLTYPE(x) (decltype(x)) -#else /* VS2008 or older (or VS2010 in C mode) */ +#else /* VS2008 or older (or VS2010 in C mode) */ #define NO_DECLTYPE #endif -#elif defined(__MCST__) /* Elbrus C Compiler */ +#elif defined(__MCST__) /* Elbrus C Compiler */ #define DECLTYPE(x) (__typeof(x)) -#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || \ + defined(__WATCOMC__) #define NO_DECLTYPE -#else /* GNU, Sun and other compilers */ +#else /* GNU, Sun and other compilers */ #define DECLTYPE(x) (__typeof(x)) #endif #endif #ifdef NO_DECLTYPE #define DECLTYPE(x) -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - char **_da_dst = (char**)(&(dst)); \ - *_da_dst = (char*)(src); \ -} while (0) +#define DECLTYPE_ASSIGN(dst, src) \ + do { \ + char **_da_dst = (char **)(&(dst)); \ + *_da_dst = (char *)(src); \ + } while (0) #else -#define DECLTYPE_ASSIGN(dst,src) \ -do { \ - (dst) = DECLTYPE(dst)(src); \ -} while (0) +#define DECLTYPE_ASSIGN(dst, src) \ + do { \ + (dst) = DECLTYPE(dst)(src); \ + } while (0) #endif #ifndef uthash_malloc -#define uthash_malloc(sz) g_malloc(sz) /* malloc fcn */ +#define uthash_malloc(sz) g_malloc(sz) /* malloc fcn */ #endif #ifndef uthash_free -#define uthash_free(ptr,sz) g_free(ptr) /* g_free fcn */ +#define uthash_free(ptr, sz) g_free(ptr) /* g_free fcn */ #endif #ifndef uthash_bzero -#define uthash_bzero(a,n) memset(a,'\0',n) +#define uthash_bzero(a, n) memset(a, '\0', n) #endif #ifndef uthash_strlen #define uthash_strlen(s) strlen(s) #endif #ifndef HASH_FUNCTION -#define HASH_FUNCTION(keyptr,keylen,hashv) HASH_JEN(keyptr, keylen, hashv) +#define HASH_FUNCTION(keyptr, keylen, hashv) HASH_JEN(keyptr, keylen, hashv) #endif #ifndef HASH_KEYCMP -#define HASH_KEYCMP(a,b,n) memcmp(a,b,n) +#define HASH_KEYCMP(a, b, n) memcmp(a, b, n) #endif #ifndef uthash_noexpand_fyi -#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #endif #ifndef uthash_expand_fyi -#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ #endif #ifndef HASH_NONFATAL_OOM @@ -107,17 +108,22 @@ do { /* malloc failures can be recovered from */ #ifndef uthash_nonfatal_oom -#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */ +#define uthash_nonfatal_oom(obj) \ + do { \ + } while (0) /* non-fatal OOM error */ #endif -#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0) +#define HASH_RECORD_OOM(oomed) \ + do { \ + (oomed) = 1; \ + } while (0) #define IF_HASH_NONFATAL_OOM(x) x #else /* malloc failures result in lost memory, hash tables are unusable */ #ifndef uthash_fatal -#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ +#define uthash_fatal(msg) exit(-1) /* fatal OOM error */ #endif #define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory") @@ -126,311 +132,335 @@ do { #endif /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ -#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ -#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 \ + 5U /* lg2 of initial number of buckets \ + */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ /* calculate the element whose hash handle address is hhp */ -#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +#define ELMT_FROM_HH(tbl, hhp) ((void *)(((char *)(hhp)) - ((tbl)->hho))) /* calculate the hash handle from element address elp */ -#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle*)(void*)(((char*)(elp)) + ((tbl)->hho))) +#define HH_FROM_ELMT(tbl, elp) \ + ((UT_hash_handle *)(void *)(((char *)(elp)) + ((tbl)->hho))) -#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ -do { \ - struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ - unsigned _hd_bkt; \ - HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - (head)->hh.tbl->buckets[_hd_bkt].count++; \ - _hd_hh_item->hh_next = NULL; \ - _hd_hh_item->hh_prev = NULL; \ -} while (0) +#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \ + do { \ + struct UT_hash_handle *_hd_hh_item = (itemptrhh); \ + unsigned _hd_bkt; \ + HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + (head)->hh.tbl->buckets[_hd_bkt].count++; \ + _hd_hh_item->hh_next = NULL; \ + _hd_hh_item->hh_prev = NULL; \ + } while (0) -#define HASH_VALUE(keyptr,keylen,hashv) \ -do { \ - HASH_FUNCTION(keyptr, keylen, hashv); \ -} while (0) +#define HASH_VALUE(keyptr, keylen, hashv) \ + do { \ + HASH_FUNCTION(keyptr, keylen, hashv); \ + } while (0) -#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_bkt; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ - if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \ - HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ - } \ - } \ -} while (0) +#define HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, hashval, out) \ + do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[_hf_bkt], \ + keyptr, keylen, hashval, out); \ + } \ + } \ + } while (0) -#define HASH_FIND(hh,head,keyptr,keylen,out) \ -do { \ - (out) = NULL; \ - if (head) { \ - unsigned _hf_hashv; \ - HASH_VALUE(keyptr, keylen, _hf_hashv); \ - HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ - } \ -} while (0) +#define HASH_FIND(hh, head, keyptr, keylen, out) \ + do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ + } \ + } while (0) #ifdef HASH_BLOOM #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) -#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) -#define HASH_BLOOM_MAKE(tbl,oomed) \ -do { \ - (tbl)->bloom_nbits = HASH_BLOOM; \ - (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ - if (!(tbl)->bloom_bv) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ - (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ - } \ -} while (0) +#define HASH_BLOOM_BYTELEN \ + (HASH_BLOOM_BITLEN / 8UL) + (((HASH_BLOOM_BITLEN % 8UL) != 0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl, oomed) \ + do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t *)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ + } while (0) -#define HASH_BLOOM_FREE(tbl) \ -do { \ - uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ -} while (0) +#define HASH_BLOOM_FREE(tbl) \ + do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + } while (0) -#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) -#define HASH_BLOOM_BITTEST(bv,idx) ((bv[(idx)/8U] & (1U << ((idx)%8U))) != 0) +#define HASH_BLOOM_BITSET(bv, idx) (bv[(idx) / 8U] |= (1U << ((idx) % 8U))) +#define HASH_BLOOM_BITTEST(bv, idx) \ + ((bv[(idx) / 8U] & (1U << ((idx) % 8U))) != 0) -#define HASH_BLOOM_ADD(tbl,hashv) \ - HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) +#define HASH_BLOOM_ADD(tbl, hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, \ + ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) -#define HASH_BLOOM_TEST(tbl,hashv) \ - HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) +#define HASH_BLOOM_TEST(tbl, hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, \ + ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) #else -#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_MAKE(tbl, oomed) #define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) -#define HASH_BLOOM_TEST(tbl,hashv) 1 +#define HASH_BLOOM_ADD(tbl, hashv) +#define HASH_BLOOM_TEST(tbl, hashv) 1 #define HASH_BLOOM_BYTELEN 0U #endif -#define HASH_MAKE_TABLE(hh,head,oomed) \ -do { \ - (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ - if (!(head)->hh.tbl) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head)->hh.tbl->tail = &((head)->hh); \ - (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ - (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ - (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ - (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - (head)->hh.tbl->signature = HASH_SIGNATURE; \ - if (!(head)->hh.tbl->buckets) { \ - HASH_RECORD_OOM(oomed); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } else { \ - uthash_bzero((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ - HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - uthash_free((head)->hh.tbl->buckets, \ - HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - } \ - ) \ - } \ - } \ -} while (0) +#define HASH_MAKE_TABLE(hh, head, oomed) \ + do { \ + (head)->hh.tbl = (UT_hash_table *)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char *)(&(head)->hh) - (char *)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket *)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ + if (!(head)->hh.tbl->buckets) { \ + HASH_RECORD_OOM(oomed); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + } else { \ + uthash_bzero((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * \ + sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \ + IF_HASH_NONFATAL_OOM(if (oomed) { \ + uthash_free((head)->hh.tbl->buckets, \ + HASH_INITIAL_NUM_BUCKETS * \ + sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + }) \ + } \ + } \ + } while (0) -#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ -} while (0) +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, \ + hashval, add, replaced, cmpfcn) \ + do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, \ + replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), \ + keylen_in, hashval, add, cmpfcn); \ + } while (0) -#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ -do { \ - (replaced) = NULL; \ - HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ - if (replaced) { \ - HASH_DELETE(hh, head, replaced); \ - } \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ -} while (0) +#define HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add, \ + replaced) \ + do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, \ + replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, \ + hashval, add); \ + } while (0) -#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ -} while (0) +#define HASH_REPLACE(hh, head, fieldname, keylen_in, add, replaced) \ + do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, \ + replaced); \ + } while (0) -#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ -do { \ - unsigned _hr_hashv; \ - HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ - HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ -} while (0) +#define HASH_REPLACE_INORDER(hh, head, fieldname, keylen_in, add, replaced, \ + cmpfcn) \ + do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, \ + _hr_hashv, add, replaced, cmpfcn); \ + } while (0) -#define HASH_APPEND_LIST(hh, head, add) \ -do { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ - (head)->hh.tbl->tail->next = (add); \ - (head)->hh.tbl->tail = &((add)->hh); \ -} while (0) +#define HASH_APPEND_LIST(hh, head, add) \ + do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ + } while (0) -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - do { \ - if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ - break; \ - } \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do { \ + do { \ + if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \ + break; \ + } \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) #ifdef NO_DECLTYPE #undef HASH_AKBI_INNER_LOOP -#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \ -do { \ - char *_hs_saved_head = (char*)(head); \ - do { \ - DECLTYPE_ASSIGN(head, _hs_iter); \ - if (cmpfcn(head, add) > 0) { \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - break; \ - } \ - DECLTYPE_ASSIGN(head, _hs_saved_head); \ - } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ -} while (0) +#define HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn) \ + do { \ + char *_hs_saved_head = (char *)(head); \ + do { \ + DECLTYPE_ASSIGN(head, _hs_iter); \ + if (cmpfcn(head, add) > 0) { \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + break; \ + } \ + DECLTYPE_ASSIGN(head, _hs_saved_head); \ + } while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \ + } while (0) #endif #if HASH_NONFATAL_OOM -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - if (!(oomed)) { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - if (oomed) { \ - HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ - HASH_DELETE_HH(hh, head, &(add)->hh); \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } else { \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ - } \ - } else { \ - (add)->hh.tbl = NULL; \ - uthash_nonfatal_oom(add); \ - } \ -} while (0) +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do { \ + if (!(oomed)) { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, \ + oomed); \ + if (oomed) { \ + HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \ + HASH_DELETE_HH(hh, head, &(add)->hh); \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } else { \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } \ + } else { \ + (add)->hh.tbl = NULL; \ + uthash_nonfatal_oom(add); \ + } \ + } while (0) #else -#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \ -do { \ - unsigned _ha_bkt; \ - (head)->hh.tbl->num_items++; \ - HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ - HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ - HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ - HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ -} while (0) +#define HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, oomed) \ + do { \ + unsigned _ha_bkt; \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + } while (0) #endif +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, \ + hashval, add, cmpfcn) \ + do { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( \ + }) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ + } while (0) -#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (char*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ - (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - void *_hs_iter = (head); \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ - if (_hs_iter) { \ - (add)->hh.next = _hs_iter; \ - if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ - HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ - } else { \ - (head) = (add); \ - } \ - HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ - } else { \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ -} while (0) +#define HASH_ADD_KEYPTR_INORDER(hh, head, keyptr, keylen_in, add, cmpfcn) \ + do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, \ + _hs_hashv, add, cmpfcn); \ + } while (0) -#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ -do { \ - unsigned _hs_hashv; \ - HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ -} while (0) +#define HASH_ADD_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, hashval, \ + add, cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), \ + keylen_in, hashval, add, cmpfcn) -#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ - HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) - -#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ +#define HASH_ADD_INORDER(hh, head, fieldname, keylen_in, add, cmpfcn) \ HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) -#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ -do { \ - IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ - (add)->hh.hashv = (hashval); \ - (add)->hh.key = (const void*) (keyptr); \ - (add)->hh.keylen = (unsigned) (keylen_in); \ - if (!(head)) { \ - (add)->hh.next = NULL; \ - (add)->hh.prev = NULL; \ - HASH_MAKE_TABLE(hh, add, _ha_oomed); \ - IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ - (head) = (add); \ - IF_HASH_NONFATAL_OOM( } ) \ - } else { \ - (add)->hh.tbl = (head)->hh.tbl; \ - HASH_APPEND_LIST(hh, head, add); \ - } \ - HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ - HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ -} while (0) +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, hashval, add) \ + do { \ + IF_HASH_NONFATAL_OOM(int _ha_oomed = 0;) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (const void *)(keyptr); \ + (add)->hh.keylen = (unsigned)(keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM(if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( \ + }) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ + } while (0) -#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ -do { \ - unsigned _ha_hashv; \ - HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ -} while (0) +#define HASH_ADD_KEYPTR(hh, head, keyptr, keylen_in, add) \ + do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ + } while (0) -#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ - HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) +#define HASH_ADD_BYHASHVALUE(hh, head, fieldname, keylen_in, hashval, add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, \ + hashval, add) -#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ +#define HASH_ADD(hh, head, fieldname, keylen_in, add) \ HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) -#define HASH_TO_BKT(hashv,num_bkts,bkt) \ -do { \ - bkt = ((hashv) & ((num_bkts) - 1U)); \ -} while (0) +#define HASH_TO_BKT(hashv, num_bkts, bkt) \ + do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ + } while (0) /* delete "delptr" from the hash table. * "the usual" patch-up process for the app-order doubly-linked-list. @@ -444,362 +474,395 @@ do { * copy the deletee pointer, then the latter references are via that * scratch pointer rather than through the repointed (users) symbol. */ -#define HASH_DELETE(hh,head,delptr) \ - HASH_DELETE_HH(hh, head, &(delptr)->hh) +#define HASH_DELETE(hh, head, delptr) HASH_DELETE_HH(hh, head, &(delptr)->hh) -#define HASH_DELETE_HH(hh,head,delptrhh) \ -do { \ - const struct UT_hash_handle *_hd_hh_del = (delptrhh); \ - if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } else { \ - unsigned _hd_bkt; \ - if (_hd_hh_del == (head)->hh.tbl->tail) { \ - (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ - } \ - if (_hd_hh_del->prev != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ - } else { \ - DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ - } \ - if (_hd_hh_del->next != NULL) { \ - HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ - } \ - HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ - HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ - (head)->hh.tbl->num_items--; \ - } \ - HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ -} while (0) +#define HASH_DELETE_HH(hh, head, delptrhh) \ + do { \ + const struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, (head)->hh.tbl->num_buckets * \ + sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = \ + _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ + } while (0) /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ -#define HASH_FIND_STR(head,findstr,out) \ -do { \ - unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ - HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ -} while (0) -#define HASH_ADD_STR(head,strfield,add) \ -do { \ - unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ -} while (0) -#define HASH_REPLACE_STR(head,strfield,add,replaced) \ -do { \ - unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ - HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ -} while (0) -#define HASH_FIND_INT(head,findint,out) \ - HASH_FIND(hh,head,findint,sizeof(int),out) -#define HASH_ADD_INT(head,intfield,add) \ - HASH_ADD(hh,head,intfield,sizeof(int),add) -#define HASH_REPLACE_INT(head,intfield,add,replaced) \ - HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) -#define HASH_FIND_PTR(head,findptr,out) \ - HASH_FIND(hh,head,findptr,sizeof(void *),out) -#define HASH_ADD_PTR(head,ptrfield,add) \ - HASH_ADD(hh,head,ptrfield,sizeof(void *),add) -#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ - HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) -#define HASH_DEL(head,delptr) \ - HASH_DELETE(hh,head,delptr) +#define HASH_FIND_STR(head, findstr, out) \ + do { \ + unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \ + HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \ + } while (0) +#define HASH_ADD_STR(head, strfield, add) \ + do { \ + unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \ + } while (0) +#define HASH_REPLACE_STR(head, strfield, add, replaced) \ + do { \ + unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \ + HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \ + } while (0) +#define HASH_FIND_INT(head, findint, out) \ + HASH_FIND(hh, head, findint, sizeof(int), out) +#define HASH_ADD_INT(head, intfield, add) \ + HASH_ADD(hh, head, intfield, sizeof(int), add) +#define HASH_REPLACE_INT(head, intfield, add, replaced) \ + HASH_REPLACE(hh, head, intfield, sizeof(int), add, replaced) +#define HASH_FIND_PTR(head, findptr, out) \ + HASH_FIND(hh, head, findptr, sizeof(void *), out) +#define HASH_ADD_PTR(head, ptrfield, add) \ + HASH_ADD(hh, head, ptrfield, sizeof(void *), add) +#define HASH_REPLACE_PTR(head, ptrfield, add, replaced) \ + HASH_REPLACE(hh, head, ptrfield, sizeof(void *), add, replaced) +#define HASH_DEL(head, delptr) HASH_DELETE(hh, head, delptr) -/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. - * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is + * defined. This is for uthash developer only; it compiles away if HASH_DEBUG + * isn't defined. */ #ifdef HASH_DEBUG -#include /* fprintf, stderr */ -#define HASH_OOPS(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) -#define HASH_FSCK(hh,head,where) \ -do { \ - struct UT_hash_handle *_thh; \ - if (head) { \ - unsigned _bkt_i; \ - unsigned _count = 0; \ - char *_prev; \ - for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ - unsigned _bkt_count = 0; \ - _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ - _prev = NULL; \ - while (_thh) { \ - if (_prev != (char*)(_thh->hh_prev)) { \ - HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ - (where), (void*)_thh->hh_prev, (void*)_prev); \ - } \ - _bkt_count++; \ - _prev = (char*)(_thh); \ - _thh = _thh->hh_next; \ - } \ - _count += _bkt_count; \ - if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ - HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ - (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ - } \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - _count = 0; \ - _prev = NULL; \ - _thh = &(head)->hh; \ - while (_thh) { \ - _count++; \ - if (_prev != (char*)_thh->prev) { \ - HASH_OOPS("%s: invalid prev %p, actual %p\n", \ - (where), (void*)_thh->prev, (void*)_prev); \ - } \ - _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ - _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ - } \ - if (_count != (head)->hh.tbl->num_items) { \ - HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ - (where), (head)->hh.tbl->num_items, _count); \ - } \ - } \ -} while (0) +#include /* fprintf, stderr */ +#define HASH_OOPS(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + exit(-1); \ + } while (0) +#define HASH_FSCK(hh, head, where) \ + do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char *)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", (where), \ + (void *)_thh->hh_prev, (void *)_prev); \ + } \ + _bkt_count++; \ + _prev = (char *)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", (where), \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", (where), \ + (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char *)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", (where), \ + (void *)_thh->prev, (void *)_prev); \ + } \ + _prev = (char *)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", (where), \ + (head)->hh.tbl->num_items, _count); \ + } \ + } \ + } while (0) #else -#define HASH_FSCK(hh,head,where) +#define HASH_FSCK(hh, head, where) #endif /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ -do { \ - unsigned _klen = fieldlen; \ - write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ - write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ -} while (0) +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) \ + do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ + } while (0) #else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#define HASH_EMIT_KEY(hh, head, keyptr, fieldlen) #endif -/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ -#define HASH_BER(key,keylen,hashv) \ -do { \ - unsigned _hb_keylen = (unsigned)keylen; \ - const unsigned char *_hb_key = (const unsigned char*)(key); \ - (hashv) = 0; \ - while (_hb_keylen-- != 0U) { \ - (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ - } \ -} while (0) - +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. + */ +#define HASH_BER(key, keylen, hashv) \ + do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char *)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ + } while (0) /* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx * (archive link: https://archive.is/Ivcan ) */ -#define HASH_SAX(key,keylen,hashv) \ -do { \ - unsigned _sx_i; \ - const unsigned char *_hs_key = (const unsigned char*)(key); \ - hashv = 0; \ - for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ - hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ - } \ -} while (0) +#define HASH_SAX(key, keylen, hashv) \ + do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_sx_i = 0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ + } while (0) /* FNV-1a variation */ -#define HASH_FNV(key,keylen,hashv) \ -do { \ - unsigned _fn_i; \ - const unsigned char *_hf_key = (const unsigned char*)(key); \ - (hashv) = 2166136261U; \ - for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ - hashv = hashv ^ _hf_key[_fn_i]; \ - hashv = hashv * 16777619U; \ - } \ -} while (0) +#define HASH_FNV(key, keylen, hashv) \ + do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char *)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i = 0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ + } while (0) -#define HASH_OAT(key,keylen,hashv) \ -do { \ - unsigned _ho_i; \ - const unsigned char *_ho_key=(const unsigned char*)(key); \ - hashv = 0; \ - for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ - hashv += _ho_key[_ho_i]; \ - hashv += (hashv << 10); \ - hashv ^= (hashv >> 6); \ - } \ - hashv += (hashv << 3); \ - hashv ^= (hashv >> 11); \ - hashv += (hashv << 15); \ -} while (0) +#define HASH_OAT(key, keylen, hashv) \ + do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key = (const unsigned char *)(key); \ + hashv = 0; \ + for (_ho_i = 0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ + } while (0) -#define HASH_JEN_MIX(a,b,c) \ -do { \ - a -= b; a -= c; a ^= ( c >> 13 ); \ - b -= c; b -= a; b ^= ( a << 8 ); \ - c -= a; c -= b; c ^= ( b >> 13 ); \ - a -= b; a -= c; a ^= ( c >> 12 ); \ - b -= c; b -= a; b ^= ( a << 16 ); \ - c -= a; c -= b; c ^= ( b >> 5 ); \ - a -= b; a -= c; a ^= ( c >> 3 ); \ - b -= c; b -= a; b ^= ( a << 10 ); \ - c -= a; c -= b; c ^= ( b >> 15 ); \ -} while (0) +#define HASH_JEN_MIX(a, b, c) \ + do { \ + a -= b; \ + a -= c; \ + a ^= (c >> 13); \ + b -= c; \ + b -= a; \ + b ^= (a << 8); \ + c -= a; \ + c -= b; \ + c ^= (b >> 13); \ + a -= b; \ + a -= c; \ + a ^= (c >> 12); \ + b -= c; \ + b -= a; \ + b ^= (a << 16); \ + c -= a; \ + c -= b; \ + c ^= (b >> 5); \ + a -= b; \ + a -= c; \ + a ^= (c >> 3); \ + b -= c; \ + b -= a; \ + b ^= (a << 10); \ + c -= a; \ + c -= b; \ + c ^= (b >> 15); \ + } while (0) -#define HASH_JEN(key,keylen,hashv) \ -do { \ - unsigned _hj_i,_hj_j,_hj_k; \ - unsigned const char *_hj_key=(unsigned const char*)(key); \ - hashv = 0xfeedbeefu; \ - _hj_i = _hj_j = 0x9e3779b9u; \ - _hj_k = (unsigned)(keylen); \ - while (_hj_k >= 12U) { \ - _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ - + ( (unsigned)_hj_key[2] << 16 ) \ - + ( (unsigned)_hj_key[3] << 24 ) ); \ - _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ - + ( (unsigned)_hj_key[6] << 16 ) \ - + ( (unsigned)_hj_key[7] << 24 ) ); \ - hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ - + ( (unsigned)_hj_key[10] << 16 ) \ - + ( (unsigned)_hj_key[11] << 24 ) ); \ - \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ - \ - _hj_key += 12; \ - _hj_k -= 12U; \ - } \ - hashv += (unsigned)(keylen); \ - switch ( _hj_k ) { \ - case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ - case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ - case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ - case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ - case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ - case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ - case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ - case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ - case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ - case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ - case 1: _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ - default: ; \ - } \ - HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ -} while (0) +#define HASH_JEN(key, keylen, hashv) \ + do { \ + unsigned _hj_i, _hj_j, _hj_k; \ + unsigned const char *_hj_key = (unsigned const char *)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ((unsigned)_hj_key[1] << 8) + \ + ((unsigned)_hj_key[2] << 16) + ((unsigned)_hj_key[3] << 24)); \ + _hj_j += (_hj_key[4] + ((unsigned)_hj_key[5] << 8) + \ + ((unsigned)_hj_key[6] << 16) + ((unsigned)_hj_key[7] << 24)); \ + hashv += \ + (_hj_key[8] + ((unsigned)_hj_key[9] << 8) + \ + ((unsigned)_hj_key[10] << 16) + ((unsigned)_hj_key[11] << 24)); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch (_hj_k) { \ + case 11: \ + hashv += ((unsigned)_hj_key[10] << 24); /* FALLTHROUGH */ \ + case 10: \ + hashv += ((unsigned)_hj_key[9] << 16); /* FALLTHROUGH */ \ + case 9: \ + hashv += ((unsigned)_hj_key[8] << 8); /* FALLTHROUGH */ \ + case 8: \ + _hj_j += ((unsigned)_hj_key[7] << 24); /* FALLTHROUGH */ \ + case 7: \ + _hj_j += ((unsigned)_hj_key[6] << 16); /* FALLTHROUGH */ \ + case 6: \ + _hj_j += ((unsigned)_hj_key[5] << 8); /* FALLTHROUGH */ \ + case 5: \ + _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: \ + _hj_i += ((unsigned)_hj_key[3] << 24); /* FALLTHROUGH */ \ + case 3: \ + _hj_i += ((unsigned)_hj_key[2] << 16); /* FALLTHROUGH */ \ + case 2: \ + _hj_i += ((unsigned)_hj_key[1] << 8); /* FALLTHROUGH */ \ + case 1: \ + _hj_i += _hj_key[0]; /* FALLTHROUGH */ \ + default:; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + } while (0) /* The Paul Hsieh hash function */ #undef get16bits -#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ - || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) -#define get16bits(d) (*((const uint16_t *) (d))) +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || \ + defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) +#define get16bits(d) (*((const uint16_t *)(d))) #endif -#if !defined (get16bits) -#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ - +(uint32_t)(((const uint8_t *)(d))[0]) ) +#if !defined(get16bits) +#define get16bits(d) \ + ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) + \ + (uint32_t)(((const uint8_t *)(d))[0])) #endif -#define HASH_SFH(key,keylen,hashv) \ -do { \ - unsigned const char *_sfh_key=(unsigned const char*)(key); \ - uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ - \ - unsigned _sfh_rem = _sfh_len & 3U; \ - _sfh_len >>= 2; \ - hashv = 0xcafebabeu; \ - \ - /* Main loop */ \ - for (;_sfh_len > 0U; _sfh_len--) { \ - hashv += get16bits (_sfh_key); \ - _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ - hashv = (hashv << 16) ^ _sfh_tmp; \ - _sfh_key += 2U*sizeof (uint16_t); \ - hashv += hashv >> 11; \ - } \ - \ - /* Handle end cases */ \ - switch (_sfh_rem) { \ - case 3: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 16; \ - hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ - hashv += hashv >> 11; \ - break; \ - case 2: hashv += get16bits (_sfh_key); \ - hashv ^= hashv << 11; \ - hashv += hashv >> 17; \ - break; \ - case 1: hashv += *_sfh_key; \ - hashv ^= hashv << 10; \ - hashv += hashv >> 1; \ - break; \ - default: ; \ - } \ - \ - /* Force "avalanching" of final 127 bits */ \ - hashv ^= hashv << 3; \ - hashv += hashv >> 5; \ - hashv ^= hashv << 4; \ - hashv += hashv >> 17; \ - hashv ^= hashv << 25; \ - hashv += hashv >> 6; \ -} while (0) +#define HASH_SFH(key, keylen, hashv) \ + do { \ + unsigned const char *_sfh_key = (unsigned const char *)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (; _sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits(_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits(_sfh_key + 2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U * sizeof(uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof(uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: \ + hashv += get16bits(_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: \ + hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + break; \ + default:; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ + } while (0) /* iterate over items in a known bucket to find desired item */ -#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ -do { \ - if ((head).hh_head != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ - } else { \ - (out) = NULL; \ - } \ - while ((out) != NULL) { \ - if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ - if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ - break; \ - } \ - } \ - if ((out)->hh.hh_next != NULL) { \ - DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ - } else { \ - (out) = NULL; \ - } \ - } \ -} while (0) +#define HASH_FIND_IN_BKT(tbl, hh, head, keyptr, keylen_in, hashval, out) \ + do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ + } while (0) /* add an item to a bucket */ -#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ -do { \ - UT_hash_bucket *_ha_head = &(head); \ - _ha_head->count++; \ - (addhh)->hh_next = _ha_head->hh_head; \ - (addhh)->hh_prev = NULL; \ - if (_ha_head->hh_head != NULL) { \ - _ha_head->hh_head->hh_prev = (addhh); \ - } \ - _ha_head->hh_head = (addhh); \ - if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \ - && !(addhh)->tbl->noexpand) { \ - HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (oomed) { \ - HASH_DEL_IN_BKT(head,addhh); \ - } \ - ) \ - } \ -} while (0) +#define HASH_ADD_TO_BKT(head, hh, addhh, oomed) \ + do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + if ((_ha_head->count >= \ + ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) && \ + !(addhh)->tbl->noexpand) { \ + HASH_EXPAND_BUCKETS(addhh, (addhh)->tbl, oomed); \ + IF_HASH_NONFATAL_OOM(if (oomed) { HASH_DEL_IN_BKT(head, addhh); }) \ + } \ + } while (0) /* remove an item from a given bucket */ -#define HASH_DEL_IN_BKT(head,delhh) \ -do { \ - UT_hash_bucket *_hd_head = &(head); \ - _hd_head->count--; \ - if (_hd_head->hh_head == (delhh)) { \ - _hd_head->hh_head = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_prev) { \ - (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ - } \ - if ((delhh)->hh_next) { \ - (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ - } \ -} while (0) +#define HASH_DEL_IN_BKT(head, delhh) \ + do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ + } while (0) /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the @@ -830,259 +893,275 @@ do { * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * */ -#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ -do { \ - unsigned _he_bkt; \ - unsigned _he_bkt_i; \ - struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ - UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ - _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - if (!_he_new_buckets) { \ - HASH_RECORD_OOM(oomed); \ - } else { \ - uthash_bzero(_he_new_buckets, \ - sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ - (tbl)->ideal_chain_maxlen = \ - ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ - ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ - (tbl)->nonideal_items = 0; \ - for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ - _he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \ - while (_he_thh != NULL) { \ - _he_hh_nxt = _he_thh->hh_next; \ - HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ - _he_newbkt = &(_he_new_buckets[_he_bkt]); \ - if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ - (tbl)->nonideal_items++; \ - if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ - _he_newbkt->expand_mult++; \ - } \ - } \ - _he_thh->hh_prev = NULL; \ - _he_thh->hh_next = _he_newbkt->hh_head; \ - if (_he_newbkt->hh_head != NULL) { \ - _he_newbkt->hh_head->hh_prev = _he_thh; \ - } \ - _he_newbkt->hh_head = _he_thh; \ - _he_thh = _he_hh_nxt; \ - } \ - } \ - uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ - (tbl)->num_buckets *= 2U; \ - (tbl)->log2_num_buckets++; \ - (tbl)->buckets = _he_new_buckets; \ - (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ - ((tbl)->ineff_expands+1U) : 0U; \ - if ((tbl)->ineff_expands > 1U) { \ - (tbl)->noexpand = 1; \ - uthash_noexpand_fyi(tbl); \ - } \ - uthash_expand_fyi(tbl); \ - } \ -} while (0) - +#define HASH_EXPAND_BUCKETS(hh, tbl, oomed) \ + do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket *)uthash_malloc( \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, \ + sizeof(struct UT_hash_bucket) * (tbl)->num_buckets * 2U); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets + 1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets * 2U) - 1U)) != 0U) \ + ? 1U \ + : 0U); \ + (tbl)->nonideal_items = 0; \ + for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \ + _he_thh = (tbl)->buckets[_he_bkt_i].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + if (_he_newbkt->count > \ + _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \ + _he_newbkt->expand_mult++; \ + } \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, \ + (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) \ + ? ((tbl)->ineff_expands + 1U) \ + : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ + } while (0) /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ /* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ -#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) -#define HASH_SRT(hh,head,cmpfcn) \ -do { \ - unsigned _hs_i; \ - unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ - struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ - if (head != NULL) { \ - _hs_insize = 1; \ - _hs_looping = 1; \ - _hs_list = &((head)->hh); \ - while (_hs_looping != 0U) { \ - _hs_p = _hs_list; \ - _hs_list = NULL; \ - _hs_tail = NULL; \ - _hs_nmerges = 0; \ - while (_hs_p != NULL) { \ - _hs_nmerges++; \ - _hs_q = _hs_p; \ - _hs_psize = 0; \ - for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ - _hs_psize++; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - if (_hs_q == NULL) { \ - break; \ - } \ - } \ - _hs_qsize = _hs_insize; \ - while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ - if (_hs_psize == 0U) { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else if ((cmpfcn( \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ - DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ - )) <= 0) { \ - _hs_e = _hs_p; \ - if (_hs_p != NULL) { \ - _hs_p = ((_hs_p->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ - } \ - _hs_psize--; \ - } else { \ - _hs_e = _hs_q; \ - _hs_q = ((_hs_q->next != NULL) ? \ - HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ - _hs_qsize--; \ - } \ - if ( _hs_tail != NULL ) { \ - _hs_tail->next = ((_hs_e != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ - } else { \ - _hs_list = _hs_e; \ - } \ - if (_hs_e != NULL) { \ - _hs_e->prev = ((_hs_tail != NULL) ? \ - ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ - } \ - _hs_tail = _hs_e; \ - } \ - _hs_p = _hs_q; \ - } \ - if (_hs_tail != NULL) { \ - _hs_tail->next = NULL; \ - } \ - if (_hs_nmerges <= 1U) { \ - _hs_looping = 0; \ - (head)->hh.tbl->tail = _hs_tail; \ - DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ - } \ - _hs_insize *= 2U; \ - } \ - HASH_FSCK(hh, head, "HASH_SRT"); \ - } \ -} while (0) +#define HASH_SORT(head, cmpfcn) HASH_SRT(hh, head, cmpfcn) +#define HASH_SRT(hh, head, cmpfcn) \ + do { \ + unsigned _hs_i; \ + unsigned _hs_looping, _hs_nmerges, _hs_insize, _hs_psize, _hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) \ + : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || \ + ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) \ + : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) \ + : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn(DECLTYPE(head)( \ + ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, \ + _hs_q)))) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) \ + : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) \ + ? HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) \ + : NULL); \ + _hs_qsize--; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = \ + ((_hs_e != NULL) ? ELMT_FROM_HH((head)->hh.tbl, _hs_e) \ + : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = \ + ((_hs_tail != NULL) ? ELMT_FROM_HH((head)->hh.tbl, _hs_tail) \ + : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ + } while (0) /* This function selects items from one hash into another hash. * The end result is that the selected items have dual presence * in both hashes. There is no copy of the items made; rather * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ -#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ -do { \ - unsigned _src_bkt, _dst_bkt; \ - void *_last_elt = NULL, *_elt; \ - UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ - ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ - if ((src) != NULL) { \ - for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ - for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ - _src_hh != NULL; \ - _src_hh = _src_hh->hh_next) { \ - _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ - if (cond(_elt)) { \ - IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ - _dst_hh = (UT_hash_handle*)(void*)(((char*)_elt) + _dst_hho); \ - _dst_hh->key = _src_hh->key; \ - _dst_hh->keylen = _src_hh->keylen; \ - _dst_hh->hashv = _src_hh->hashv; \ - _dst_hh->prev = _last_elt; \ - _dst_hh->next = NULL; \ - if (_last_elt_hh != NULL) { \ - _last_elt_hh->next = _elt; \ - } \ - if ((dst) == NULL) { \ - DECLTYPE_ASSIGN(dst, _elt); \ - HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - uthash_nonfatal_oom(_elt); \ - (dst) = NULL; \ - continue; \ - } \ - ) \ - } else { \ - _dst_hh->tbl = (dst)->hh_dst.tbl; \ - } \ - HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ - HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ - (dst)->hh_dst.tbl->num_items++; \ - IF_HASH_NONFATAL_OOM( \ - if (_hs_oomed) { \ - HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ - HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ - _dst_hh->tbl = NULL; \ - uthash_nonfatal_oom(_elt); \ - continue; \ - } \ - ) \ - HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ - _last_elt = _elt; \ - _last_elt_hh = _dst_hh; \ - } \ - } \ - } \ - } \ - HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ -} while (0) +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ + do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh = NULL; \ + ptrdiff_t _dst_hho = ((char *)(&(dst)->hh_dst) - (char *)(dst)); \ + if ((src) != NULL) { \ + for (_src_bkt = 0; _src_bkt < (src)->hh_src.tbl->num_buckets; \ + _src_bkt++) { \ + for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM(int _hs_oomed = 0;) \ + _dst_hh = (UT_hash_handle *)(void *)(((char *)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + if ((dst) == NULL) { \ + DECLTYPE_ASSIGN(dst, _elt); \ + HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \ + IF_HASH_NONFATAL_OOM(if (_hs_oomed) { \ + uthash_nonfatal_oom(_elt); \ + (dst) = NULL; \ + continue; \ + }) \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, \ + _hs_oomed); \ + (dst)->hh_dst.tbl->num_items++; \ + IF_HASH_NONFATAL_OOM(if (_hs_oomed) { \ + HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \ + HASH_DELETE_HH(hh_dst, dst, _dst_hh); \ + _dst_hh->tbl = NULL; \ + uthash_nonfatal_oom(_elt); \ + continue; \ + }) \ + HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ + } while (0) -#define HASH_CLEAR(hh,head) \ -do { \ - if ((head) != NULL) { \ - HASH_BLOOM_FREE((head)->hh.tbl); \ - uthash_free((head)->hh.tbl->buckets, \ - (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ - uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ - (head) = NULL; \ - } \ -} while (0) +#define HASH_CLEAR(hh, head) \ + do { \ + if ((head) != NULL) { \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl->buckets, (head)->hh.tbl->num_buckets * \ + sizeof(struct UT_hash_bucket)); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head) = NULL; \ + } \ + } while (0) -#define HASH_OVERHEAD(hh,head) \ - (((head) != NULL) ? ( \ - (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ - ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ - sizeof(UT_hash_table) + \ - (HASH_BLOOM_BYTELEN))) : 0U) +#define HASH_OVERHEAD(hh, head) \ + (((head) != NULL) \ + ? ((size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + (HASH_BLOOM_BYTELEN))) \ + : 0U) #ifdef NO_DECLTYPE -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), \ + ((*(char **)(&(tmp))) = \ + (char *)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; \ + ((el) = (tmp)), ((*(char **)(&(tmp))) = \ + (char *)((tmp != NULL) ? (tmp)->hh.next : NULL))) #else -#define HASH_ITER(hh,head,el,tmp) \ -for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ - (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#define HASH_ITER(hh, head, el, tmp) \ + for (((el) = (head)), \ + ((tmp) = DECLTYPE(el)((head != NULL) ? (head)->hh.next : NULL)); \ + (el) != NULL; \ + ((el) = (tmp)), \ + ((tmp) = DECLTYPE(el)((tmp != NULL) ? (tmp)->hh.next : NULL))) #endif /* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) -#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) +#define HASH_COUNT(head) HASH_CNT(hh, head) +#define HASH_CNT(hh, head) ((head != NULL) ? ((head)->hh.tbl->num_items) : 0U) typedef struct UT_hash_bucket { - struct UT_hash_handle *hh_head; - unsigned count; + struct UT_hash_handle *hh_head; + unsigned count; - /* expand_mult is normally set to 0. In this situation, the max chain length - * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). - * However, setting expand_mult to a non-zero value delays bucket expansion - * (that would be triggered by additions to this particular bucket) - * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. - * (The multiplier is simply expand_mult+1). The whole idea of this - * multiplier is to reduce bucket expansions, since they are expensive, in - * situations where we know that a particular bucket tends to be overused. - * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. - */ - unsigned expand_mult; + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; } UT_hash_bucket; @@ -1091,47 +1170,47 @@ typedef struct UT_hash_bucket { #define HASH_BLOOM_SIGNATURE 0xb12220f2u typedef struct UT_hash_table { - UT_hash_bucket *buckets; - unsigned num_buckets, log2_num_buckets; - unsigned num_items; - struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ - ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ - /* in an ideal situation (all buckets used equally), no bucket would have - * more than ceil(#items/#buckets) items. that's the ideal chain length. */ - unsigned ideal_chain_maxlen; + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; - /* nonideal_items is the number of items in the hash whose chain position - * exceeds the ideal chain maxlen. these items pay the penalty for an uneven - * hash distribution; reaching them in a chain traversal takes >ideal steps */ - unsigned nonideal_items; + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; - /* ineffective expands occur when a bucket doubling was performed, but - * afterward, more than half the items in the hash had nonideal chain - * positions. If this happens on two consecutive expansions we inhibit any - * further expansion, as it's not helping; this happens when the hash - * function isn't a good fit for the key domain. When expansion is inhibited - * the hash will still work, albeit no longer in constant time. */ - unsigned ineff_expands, noexpand; + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; - uint32_t signature; /* used only to find hash tables in external analysis */ + uint32_t signature; /* used only to find hash tables in external analysis */ #ifdef HASH_BLOOM - uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ - uint8_t *bloom_bv; - uint8_t bloom_nbits; + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; #endif } UT_hash_table; typedef struct UT_hash_handle { - struct UT_hash_table *tbl; - void *prev; /* prev element in app order */ - void *next; /* next element in app order */ - struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ - struct UT_hash_handle *hh_next; /* next hh in bucket order */ - const void *key; /* ptr to enclosing struct's key */ - unsigned keylen; /* enclosing struct's key len */ - unsigned hashv; /* result of hash-fcn(key) */ + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + const void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ } UT_hash_handle; #endif /* UTHASH_H */ diff --git a/Core/transmit_protocol/warp_kcp/warp_kcp.cpp b/Core/transmit_protocol/warp_kcp/warp_kcp.cpp index ec99325..5980de0 100644 --- a/Core/transmit_protocol/warp_kcp/warp_kcp.cpp +++ b/Core/transmit_protocol/warp_kcp/warp_kcp.cpp @@ -2,91 +2,84 @@ // 要把out_put 的缓存然后使用 合适的时机由 下层函数发送 -int warp_kcp_output(const char* buf, int len, struct KCPCB* kcp, void* user); +int warp_kcp_output(const char *buf, int len, struct KCPCB *kcp, void *user); +int warp_kcp_output(const char *buf, int len, struct KCPCB *kcp, void *user) { + auto cb = (Warp_KCP *)user; + // printf("[send] kcp_send len:%u \r\n", len); - - - -int warp_kcp_output(const char* buf, int len, struct KCPCB* kcp, void* user){ - auto cb = (Warp_KCP*)user; - - - // printf("[send] kcp_send len:%u \r\n", len); - - cb->next_send((Base_CB*)cb, (Buf_Type)buf, len, cb->pn); - return len; + cb->next_send((Base_CB *)cb, (Buf_Type)buf, len, cb->pn); + return len; } Warp_KCP::Warp_KCP(IUINT32 conv, Get_Millisecond get_millisecond) { - this->get_millisecond = get_millisecond; - kcp = kcp_create(conv, this); - kcp->output = warp_kcp_output; - kcp_wndsize(kcp, 128, 128); - int mode = 2; - // 判断测试用例的模式 - if (mode == 0) { - // 默认模式 - kcp_nodelay(kcp, 0, 10, 0, 0); - } else if (mode == 1) { - // 普通模式,关闭流控等 - kcp_nodelay(kcp, 0, 10, 0, 1); - } else { - // 启动快速模式 - // 第二个参数 nodelay-启用以后若干常规加速将启动 - // 第三个参数 interval为内部处理时钟,默认设置为 10ms - // 第四个参数 resend为快速重传指标,设置为2 - // 第五个参数 为是否禁用常规流控,这里禁止 - kcp_nodelay(kcp, 3, 10, 2, 1); - kcp->rx_minrto = 10; - kcp->fastresend = 1; - kcp->fastlimit = 10000; - kcp->rx_rto = 20; - int factor = 1; - kcp_wndsize(kcp, factor * 32, factor * 128); - } + this->get_millisecond = get_millisecond; + kcp = kcp_create(conv, this); + kcp->output = warp_kcp_output; + kcp_wndsize(kcp, 128, 128); + int mode = 2; + // 判断测试用例的模式 + if (mode == 0) { + // 默认模式 + kcp_nodelay(kcp, 0, 10, 0, 0); + } else if (mode == 1) { + // 普通模式,关闭流控等 + kcp_nodelay(kcp, 0, 10, 0, 1); + } else { + // 启动快速模式 + // 第二个参数 nodelay-启用以后若干常规加速将启动 + // 第三个参数 interval为内部处理时钟,默认设置为 10ms + // 第四个参数 resend为快速重传指标,设置为2 + // 第五个参数 为是否禁用常规流控,这里禁止 + kcp_nodelay(kcp, 3, 10, 2, 1); + kcp->rx_minrto = 10; + kcp->fastresend = 1; + kcp->fastlimit = 10000; + kcp->rx_rto = 20; + int factor = 1; + kcp_wndsize(kcp, factor * 32, factor * 128); + } } Warp_KCP::~Warp_KCP() { kcp_release(kcp); } - -void Warp_KCP::send(Buf_Type buf, Len_Type len, void* user) { - update(); - last_user = user; - int ret = kcp_send(kcp, buf, len); - if (ret < 0) { - printf("ikcp_send failed %d \n", ret); - } +void Warp_KCP::send(Buf_Type buf, Len_Type len, void *user) { + update(); + last_user = user; + int ret = kcp_send(kcp, buf, len); + if (ret < 0) { + printf("ikcp_send failed %d \n", ret); + } } -void Warp_KCP::recv(Buf_Type buf, Len_Type len, void* user) { - update(); - if (kcp->cwnd < 20) { - kcp->cwnd = 20; - } - int l = kcp_input(kcp, buf, len); - if (l < 0) { - printf("Warp_KCP_recv wrong input: %d\n", l); - } +void Warp_KCP::recv(Buf_Type buf, Len_Type len, void *user) { + update(); + if (kcp->cwnd < 20) { + kcp->cwnd = 20; + } + int l = kcp_input(kcp, buf, len); + if (l < 0) { + printf("Warp_KCP_recv wrong input: %d\n", l); + } #ifdef Transmit_Protocol_Debug - printf("Warp_KCP_recv : %d\n", l); + printf("Warp_KCP_recv : %d\n", l); #endif - // printf("kcp_input len:%u ret:%u \r\n", len, l); - char buffer[4096]; - while (1) { - int r = kcp_recv(kcp, buffer, 4096); - if (r < 0) return; - next_recv(this, buffer, r, user); - } + // printf("kcp_input len:%u ret:%u \r\n", len, l); + char buffer[4096]; + while (1) { + int r = kcp_recv(kcp, buffer, 4096); + if (r < 0) + return; + next_recv(this, buffer, r, user); + } } void Warp_KCP::update() { - kcpcb* kcb = kcp; - IUINT32 current = get_millisecond(); - if (current > update_time) { - update_time = kcp_check(kcb, current); - kcp_update(kcb, current); + kcpcb *kcb = kcp; + IUINT32 current = get_millisecond(); + if (current > update_time) { + update_time = kcp_check(kcb, current); + kcp_update(kcb, current); + } - } - - // TODO: 可能为什么调用少了就不行了 - //ikcp_flush(kcb); + // TODO: 可能为什么调用少了就不行了 + // ikcp_flush(kcb); } diff --git a/Core/transmit_protocol/warp_kcp/warp_kcp.h b/Core/transmit_protocol/warp_kcp/warp_kcp.h index 1d6f198..2e70847 100644 --- a/Core/transmit_protocol/warp_kcp/warp_kcp.h +++ b/Core/transmit_protocol/warp_kcp/warp_kcp.h @@ -1,17 +1,16 @@ #pragma once - #include "../global.h" #include "./kcp.h" struct Warp_KCP : Base_CB { - void* last_user{}; - kcpcb* kcp{}; - Get_Millisecond get_millisecond{}; - IUINT32 update_time = 0; - Warp_KCP(IUINT32 conv, Get_Millisecond get_millisecond); - ~Warp_KCP() override; - void send(Buf_Type buf, Len_Type len, void* user) override; - void recv(Buf_Type buf, Len_Type len, void* user) override; - void update() override; + void *last_user{}; + kcpcb *kcp{}; + Get_Millisecond get_millisecond{}; + IUINT32 update_time = 0; + Warp_KCP(IUINT32 conv, Get_Millisecond get_millisecond); + ~Warp_KCP() override; + void send(Buf_Type buf, Len_Type len, void *user) override; + void recv(Buf_Type buf, Len_Type len, void *user) override; + void update() override; }; diff --git a/Core/transmit_protocol/协议分析文档.md b/Core/transmit_protocol/协议分析文档.md index 5faead1..ff7b94b 100644 --- a/Core/transmit_protocol/协议分析文档.md +++ b/Core/transmit_protocol/协议分析文档.md @@ -1,103 +1,86 @@ - - - - ## 依赖协议类型 -| 协议 | 流/包 | 必达性 | 顺序保证 | 数据正确性 | -|---------------|-----|-------|------|-------------------------------| -| 串口 | 流 | ❌ | ✅ | ❌ | -| RTP(裸) | 包 | ❌ | ❌ | ❌ | -| 以太网帧 | 包 | ❌ | ❌ | ✅ | -| IP(IPv4/IPv6)| 包 | ❌ | ❌ | ❌(IP 协议本身只保证头部完整性,并不保证数据区无损坏) | -| UDP | 包 | ❌ | ❌ | ✅ | -| TCP | 流 | ✅ | ✅ | ✅ | -| USB Bulk | 包 | ✅ | ✅ | ✅ | -| KCP | 包 | ✅ | ✅ | ✅ | -| SCTP(多流) | 包 | ✅ | ✅ | ✅ | +| 协议 | 流/包 | 必达性 | 顺序保证 | 数据正确性 | +|---------------|-----|-----|------|-------------------------------| +| 串口 | 流 | ❌ | ✅ | ❌ | +| RTP(裸) | 包 | ❌ | ❌ | ❌ | +| 以太网帧 | 包 | ❌ | ❌ | ✅ | +| IP(IPv4/IPv6) | 包 | ❌ | ❌ | ❌(IP 协议本身只保证头部完整性,并不保证数据区无损坏) | +| UDP | 包 | ❌ | ❌ | ✅ | +| TCP | 流 | ✅ | ✅ | ✅ | +| USB Bulk | 包 | ✅ | ✅ | ✅ | +| KCP | 包 | ✅ | ✅ | ✅ | +| SCTP(多流) | 包 | ✅ | ✅ | ✅ | 所有数据协议都是这种结构, 可以基于此协议实现(包/流)✅✅✅ 特性的协议 - ## 枚举物理特性类型 -| 类型 | 特点 | 例子 | -|-----------------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------| -| 网络拥堵型 (Congestion-prone) | 数据量接近带宽上限时会拥堵、排队、丢包,延迟增加 | 以太网、IP 网络、交换机/路由器链路 | -| 稳定误码型 (Constant Error Rate) | 错误率稳定,发送速率不影响误码率 | 串口(UART/RS-232)、光纤点对点链路 | -| 高延迟型 (High Latency) | 延迟几乎固定,带宽可能大,但 ACK/重传回路很慢 | 卫星通信、深空探测链路(NASA 深空网络)、洲际光缆 | -| 抖动型 (Jitter-prone) | 传输延迟不稳定,包延迟波动大,适合平均速率控制,不适合严格定时 | 无线链路(4G/5G/Wi-Fi)、共享交换机低优先级端口 | -| 突发丢包型 (Burst Loss) | 丢包连续发生,需 FEC(前向纠错)或交织(Interleaving)抵抗 | 无线广播、多播视频流、光纤瞬间闪断 | -| 自适应速率型 (Rate Adaptive) | 链路带宽动态变化,需快速检测并调整传输速率 | DSL、Wi-Fi(MCS 调制速率变化)、移动蜂窝网络 | -| 半双工限制型 (Half-duplex) | 同一时刻只能收或发,需要收发切换时机,ACK/数据抢占带宽 | 老式对讲机、RS-485 总线、卫星上行/下行同频时分 | -| 多路径干扰型 (Multipath Fading) | 信号多路径到达互相干扰,误码集中在特定时间段,需频率跳变或纠错码 | 移动无线通信、海面反射、建筑反射 | + +| 类型 | 特点 | 例子 | +|-----------------------------|---------------------------------------|-------------------------------| +| 网络拥堵型 (Congestion-prone) | 数据量接近带宽上限时会拥堵、排队、丢包,延迟增加 | 以太网、IP 网络、交换机/路由器链路 | +| 稳定误码型 (Constant Error Rate) | 错误率稳定,发送速率不影响误码率 | 串口(UART/RS-232)、光纤点对点链路 | +| 高延迟型 (High Latency) | 延迟几乎固定,带宽可能大,但 ACK/重传回路很慢 | 卫星通信、深空探测链路(NASA 深空网络)、洲际光缆 | +| 抖动型 (Jitter-prone) | 传输延迟不稳定,包延迟波动大,适合平均速率控制,不适合严格定时 | 无线链路(4G/5G/Wi-Fi)、共享交换机低优先级端口 | +| 突发丢包型 (Burst Loss) | 丢包连续发生,需 FEC(前向纠错)或交织(Interleaving)抵抗 | 无线广播、多播视频流、光纤瞬间闪断 | +| 自适应速率型 (Rate Adaptive) | 链路带宽动态变化,需快速检测并调整传输速率 | DSL、Wi-Fi(MCS 调制速率变化)、移动蜂窝网络 | +| 半双工限制型 (Half-duplex) | 同一时刻只能收或发,需要收发切换时机,ACK/数据抢占带宽 | 老式对讲机、RS-485 总线、卫星上行/下行同频时分 | +| 多路径干扰型 (Multipath Fading) | 信号多路径到达互相干扰,误码集中在特定时间段,需频率跳变或纠错码 | 移动无线通信、海面反射、建筑反射 | ## 物理特性抽象 -虽然物理特性种类繁杂,但是我们只能应用软件手段,软件手段有以下几种 -1.抗差错编码 -2.拥塞控制 传输给物理链路数据的 频率,速度,大小等 +虽然物理特性种类繁杂,但是我们只能应用软件手段,软件手段有以下几种 +1.抗差错编码 +2.拥塞控制 传输给物理链路数据的 频率,速度,大小等 kcp协议的底层依赖是udp类型的协议,一种无序,分包,非必达,保证数据正确的协议。 其中抗差错编码就可以做在这个底层协议上,外包给别人做。 kcp可以只专注于拥塞控制,对外提供可靠传输 - 所以这些物理特性总体来看可以看做可靠性和其他特性的关联函数 又分为两类 -一类是 误码率与拥塞控制相关, 这是应该控制发包的流速调整方向和相关方向一致 -一类是 误码率与拥塞控制无关, 这是应该忽略影响,尽量达到最大流量限制 - - - +一类是 误码率与拥塞控制相关, 这是应该控制发包的流速调整方向和相关方向一致 +一类是 误码率与拥塞控制无关, 这是应该忽略影响,尽量达到最大流量限制 [KCP最佳实践](https://github.com/skywind3000/kcp/wiki/Network-Layer) - - -rto策略 真实使用rto msg->rto -1、kcp->rx_rto 全局的参考 RTO 基准值 是msg->rto初始值 根据网络抖动、均值,更新 +rto策略 真实使用rto msg->rto +1、kcp->rx_rto 全局的参考 RTO 基准值 是msg->rto初始值 根据网络抖动、均值,更新 实现在static void ikcp_update_ack(ikcpcb *kcp, IINT32 rtt) 2、msg->rto 根据丢包自动增长策略(kcp->nodelay控制) resendts是一个确切的重传时间点 根据 current 和 rto - - kcp xmit 记录重传的次数,包括快速重传 - -kcp快速重传判断机制 ikcp_parse_fastack() 这里面增加 msg->fastack -msg->fastack 快速重传权重值 -kcp->fastresend; 快速重传阈值,msg->fastack达到这个值就重传一次 +kcp快速重传判断机制 ikcp_parse_fastack() 这里面增加 msg->fastack +msg->fastack 快速重传权重值 +kcp->fastresend; 快速重传阈值,msg->fastack达到这个值就重传一次 kcp->fastlimit 快速重传最大次数 - kcp丢包判断机制 每个包都有自己的 msg->rto 倒计时器 如果当前时间 current >= seg->resendts(重传时间戳),就认为确实丢包了 - - -我改成了最大值,使得快速重传无次数限制 const IUINT32 IKCP_FASTACK_LIMIT = -1; // max times to trigger fastack - +我改成了最大值,使得快速重传无次数限制 const IUINT32 IKCP_FASTACK_LIMIT = -1; // max times to trigger fastack #### send 发送是先进队列 再进 snd_buf + #### recv 发送是先进buf 再进 队列 snd_buf 是 已经发送出去但还没收到 ACK 的包的链表(按 sn 从小到大排序) rev_buf 是 未与rcv_nxt做连接的,非等间隔递增 ACK 的包的链表 // 这三个变量分析 -snd_una 含义:最早未被确认(ACK)的发送序号 由ikcp_shrink_buf更新,从snd_buf取出最左边的处理 -snd_nxt 含义:下一个要发送的序号 -rcv_nxt 含义:接收方期望收到的下一个序号 - +snd_una 含义:最早未被确认(ACK)的发送序号 由ikcp_shrink_buf更新,从snd_buf取出最左边的处理 +snd_nxt 含义:下一个要发送的序号 +rcv_nxt 含义:接收方期望收到的下一个序号 kcp 回绕问题 KCP 的解决方法 KCP 里所有序号比较都不会直接用 sn1 > sn2 这种逻辑,而是用 _itimediff(a, b) static inline long _itimediff(IUINT32 later, IUINT32 earlier) { - return ((IINT32)(later - earlier)); +return ((IINT32)(later - earlier)); } KCP 的序号比较是环形空间,假设包延迟或乱序不会超过 2^31 序号跨度(约 21 亿包),那么判断是安全的。 diff --git a/Core/transmit_protocol/性能测试记录/性能测试记录.md b/Core/transmit_protocol/性能测试记录/性能测试记录.md index 8207608..f808d0c 100644 --- a/Core/transmit_protocol/性能测试记录/性能测试记录.md +++ b/Core/transmit_protocol/性能测试记录/性能测试记录.md @@ -1,5 +1,5 @@ - #### 在下列随机参数下 + ``` srand((unsigned)time(NULL)); int base = 800; @@ -7,14 +7,12 @@ send_packet(c0, base + jitter); ``` - #### 单独的udp_fec测试结果 + ![](udp_fec_on_800_1000.png) - - #### 带有kcp的udp_fec测试结果 + ![](kcp__udp_fec_on_800_1000.png) - ![](kcp__udp_fec_on_800_1000_%E8%87%AA%E5%8A%A8%E8%B0%83%E6%95%B4%E7%AE%97%E6%B3%95.png) diff --git a/Core/transmit_protocol/文档.md b/Core/transmit_protocol/文档.md index ca99048..949ac2b 100644 --- a/Core/transmit_protocol/文档.md +++ b/Core/transmit_protocol/文档.md @@ -1,33 +1,22 @@ 网络协议KCP/QUIC/TCP对比测试 - adwpc的文章 - 知乎 https://zhuanlan.zhihu.com/p/387034743 - https://github.com/skywind3000/kcp - - MOBA类游戏是如何解决网络延迟同步的? - 胡帆的回答 - 知乎 https://www.zhihu.com/question/36258781/answer/80841137 - https://www.cnblogs.com/hellozhangjz/p/18075534 - https://blog.csdn.net/m0_46833172/article/details/130932364 - 目前有如下的开源程序实现利用UDP实现了可靠的数据传输。分别为RUDP、RTP、UDT。 - - https://blog.csdn.net/n5/article/details/78934614 - [小林图解TCP](https://xiaolincoding.com/network/3_tcp/tcp_interview.html) [千兆以太网极限传输速度计算与分析](https://blog.kuretru.com/posts/4b2e81e8/) - - -这是一个纯C库要求 要求能移植到嵌入式上 +这是一个纯C库要求 要求能移植到嵌入式上 diff --git a/Socket_old/Socket_p.h b/Socket_old/Socket_p.h index 7c8ad34..82efc7c 100644 --- a/Socket_old/Socket_p.h +++ b/Socket_old/Socket_p.h @@ -5,7 +5,6 @@ #ifdef WIN32 #include #include -#pragma comment(lib, "Ws2_32.lib") namespace { struct InitializeWinsock { InitializeWinsock() { diff --git a/main.cmake b/main.cmake index b8c81d3..eb223d1 100644 --- a/main.cmake +++ b/main.cmake @@ -165,7 +165,9 @@ if(WIN32) psapi shell32 dbghelp + iphlpapi ) + endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux")