diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bdedcf..c692cd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,6 @@ set(dependencies esp_system # esp_http_client esp_websocket_client - libsodium tcp_transport cpputils diff --git a/src/espstrutils.cpp b/src/espstrutils.cpp index 70b4dde..dec6b90 100644 --- a/src/espstrutils.cpp +++ b/src/espstrutils.cpp @@ -7,7 +7,6 @@ // esp-idf includes #include -#include // 3rdparty lib includes #include @@ -15,10 +14,21 @@ // local includes #include "futurecpp.h" +using namespace std::string_literals; + namespace espcpputils { namespace { constexpr const char * const TAG = "ESPCPPUTILS"; -} + +tl::expected sodium_bin2hex(char * const hex, const size_t hex_maxlen, + const unsigned char * const bin, const size_t bin_len) + __attribute__ ((nonnull(1))); +tl::expected sodium_hex2bin(unsigned char * const bin, const size_t bin_maxlen, + const char * const hex, const size_t hex_len, + const char * const ignore, size_t * const bin_len, + const char ** const hex_end) + __attribute__ ((nonnull(1))); +} // namespace std::string toString(sntp_sync_mode_t val) { @@ -87,7 +97,12 @@ std::string toHexString(std::basic_string_view buf) std::string hex(buf.size() * 2 + 1, {}); assert(hex.size() == buf.size() * 2 + 1); - sodium_bin2hex(hex.data(), hex.size(), buf.data(), buf.size()); + if (const auto result = sodium_bin2hex(hex.data(), hex.size(), buf.data(), buf.size()); !result) + { + auto msg = fmt::format("sodium_bin2hex() failed with {}", result.error()); + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + return {}; + } hex.resize(hex.size() - 1); assert(hex.size() == buf.size() * 2); @@ -101,10 +116,11 @@ tl::expected, std::string> fromHexString(s uint8_t binBuf[binMaxLen]; size_t binLen; - if (const auto result = sodium_hex2bin(binBuf, binMaxLen, str.data(), str.size(), NULL, &binLen, NULL); result != 0) + if (const auto result = sodium_hex2bin(binBuf, binMaxLen, str.data(), str.size(), NULL, &binLen, NULL); !result) { - ESP_LOGW(TAG, "sodium_hex2bin() failed with %i", result); - return tl::make_unexpected(fmt::format("sodium_hex2bin() failed with {}", result)); + auto msg = fmt::format("sodium_hex2bin() failed with {}", result.error()); + ESP_LOGW(TAG, "%.*s", msg.size(), msg.data()); + return tl::make_unexpected(std::move(msg)); } if (binLen != str.size() / 2) @@ -118,4 +134,93 @@ tl::expected, std::string> fromHexString(s return bin; } +namespace { +/* Derived from original code by CodesInChaos */ +tl::expected +sodium_bin2hex(char *const hex, const size_t hex_maxlen, + const unsigned char *const bin, const size_t bin_len) +{ + size_t i = (size_t) 0U; + unsigned int x; + int b; + int c; + + if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) { + return tl::make_unexpected("misuse because bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U"); + } + while (i < bin_len) { + c = bin[i] & 0xf; + b = bin[i] >> 4; + x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 | + (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U)); + hex[i * 2U] = (char) x; + x >>= 8; + hex[i * 2U + 1U] = (char) x; + i++; + } + hex[i * 2U] = 0U; + + return hex; +} + +tl::expected +sodium_hex2bin(unsigned char *const bin, const size_t bin_maxlen, + const char *const hex, const size_t hex_len, + const char *const ignore, size_t *const bin_len, + const char **const hex_end) +{ + size_t bin_pos = (size_t) 0U; + size_t hex_pos = (size_t) 0U; + tl::expected ret; + unsigned char c; + unsigned char c_acc = 0U; + unsigned char c_alpha0, c_alpha; + unsigned char c_num0, c_num; + unsigned char c_val; + unsigned char state = 0U; + + while (hex_pos < hex_len) { + c = (unsigned char) hex[hex_pos]; + c_num = c ^ 48U; + c_num0 = (c_num - 10U) >> 8; + c_alpha = (c & ~32U) - 55U; + c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8; + if ((c_num0 | c_alpha0) == 0U) { + if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) { + hex_pos++; + continue; + } + break; + } + c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha); + if (bin_pos >= bin_maxlen) { + ret = tl::make_unexpected("ERANGE because bin_pos >= bin_maxlen"s); + break; + } + if (state == 0U) { + c_acc = c_val * 16U; + } else { + bin[bin_pos++] = c_acc | c_val; + } + state = ~state; + hex_pos++; + } + if (state != 0U) { + hex_pos--; + ret = tl::make_unexpected("EINVAL because state != 0U"s); + } + if (!ret) { + bin_pos = (size_t) 0U; + } + if (hex_end != NULL) { + *hex_end = &hex[hex_pos]; + } else if (hex_pos != hex_len) { + ret = tl::make_unexpected("EINVAL because hex_pos != hex_len"s); + } + if (bin_len != NULL) { + *bin_len = bin_pos; + } + return ret; +} +} // namespace } // namespace espcpputils diff --git a/src/wrappers/websocket_client.h b/src/wrappers/websocket_client.h index 8ea4bb1..afba826 100644 --- a/src/wrappers/websocket_client.h +++ b/src/wrappers/websocket_client.h @@ -38,8 +38,6 @@ public: esp_err_t set_uri (std::string_view uri) { return esp_websocket_client_set_uri (handle, uri.data()); } esp_err_t start () { return esp_websocket_client_start (handle); } esp_err_t stop () { return esp_websocket_client_stop (handle); } - //int send (const char *data, int len, TickType_t timeout) { return esp_websocket_client_send (handle, data, len, timeout); } - int send (std::string_view buf, TickType_t timeout) { return esp_websocket_client_send (handle, buf.data(), buf.size(), timeout); } //int send_bin (const char *data, int len, TickType_t timeout) { return esp_websocket_client_send_bin (handle, data, len, timeout); } int send_bin (std::string_view buf, TickType_t timeout) { return esp_websocket_client_send_bin (handle, buf.data(), buf.size(), timeout); } //int send_text (const char *data, int len, TickType_t timeout) { return esp_websocket_client_send_text (handle, data, len, timeout); }