diff --git a/.vscode/launch.json b/.vscode/launch.json index 17e1d00a..a70a919a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -38,6 +38,26 @@ "target": "${workspaceRoot}/build_gcc_native/tests/chargepoint/smartcharging/test_smartcharging_setpoint", "cwd": "${workspaceRoot}", "valuesFormatting": "parseText" + }, + { + "type": "cppdbg", + "request": "attach", + "name": "Join process", + "program": "${workspaceRoot}/bin/gcc_native/quick_start_chargepoint", + "processId": "${command:pickProcess}", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer l'impression en mode Pretty pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Définir la version désassemblage sur Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] } ] } \ No newline at end of file diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 8624745a..5d239349 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -8,11 +8,15 @@ endif() target_include_directories(rapidjson INTERFACE rapidjson/include) # Doctest is an header only on library -add_library(doctest INTERFACE) -target_include_directories(doctest INTERFACE doctest/doctest) +if(${INSTALL_DOCTEST}) + add_library(doctest INTERFACE) + target_include_directories(doctest INTERFACE doctest/doctest) +endif() # SQLite 3 -add_subdirectory(sqlite3) +if(${BUILD_SQLITE}) + add_subdirectory(sqlite3) +endif() # libwebsockets if(${BUILD_LWS_LIBRARY}) diff --git a/CMakeLists.txt b/CMakeLists.txt index cff2b913..f922e71d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.13) project(OpenOCPP DESCRIPTION "Open Source C++ implementation of the OCPP 1.6 protocol" - VERSION 1.4.3 + VERSION 1.5.0 ) # Definitions for Version.h file @@ -89,29 +89,32 @@ if(${BUILD_STATIC_LIBRARY}) endif() # Open OCPP dynamic library -add_library(open-ocpp-dynamic SHARED - src/version.cpp) -target_link_libraries(open-ocpp-dynamic - centralsystem - chargepoint - localcontroller - config - database - messages - rpc - helpers - log - version - x509 - json - ws - websockets -) -set_target_properties(open-ocpp-dynamic PROPERTIES - OUTPUT_NAME "open-ocpp" - VERSION ${PROJECT_VERSION} - SOVERSION ${PROJECT_VERSION_MAJOR} -) +if (${BUILD_SHARED_LIBRARY}) + add_library(open-ocpp-dynamic SHARED + src/version.cpp) + target_link_libraries(open-ocpp-dynamic + centralsystem + chargepoint + localcontroller + config + database + messages + rpc + helpers + log + version + x509 + json + ws + websockets + ) + set_target_properties(open-ocpp-dynamic PROPERTIES + OUTPUT_NAME "open-ocpp" + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) + set(OPEN_OCPP_SHARED_TARGET open-ocpp-dynamic) +endif() # Install commands include(GNUInstallDirs) @@ -121,7 +124,7 @@ file(GLOB_RECURSE PUBLIC_HEADERS file(GLOB OCPP_SCHEMAS LIST_DIRECTORIES false RELATIVE ${CMAKE_SOURCE_DIR} "${CMAKE_SOURCE_DIR}/schemas/*.json") -install(TARGETS open-ocpp-dynamic ${OPEN_OCPP_STATIC_TARGET} +install(TARGETS ${OPEN_OCPP_SHARED_TARGET} ${OPEN_OCPP_STATIC_TARGET} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -145,12 +148,14 @@ set(PKG_CONFIG_INCLUDEDIR "\${prefix}/include/openocpp") set(PKG_CONFIG_LIBS "-L\${libdir}") set(PKG_CONFIG_CFLAGS "-I\${includedir}") -set(LIB_NAME "open-ocpp") -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/deploy/libopen-ocpp.pc.in" - "${CMAKE_CURRENT_BINARY_DIR}/libopen-ocpp.pc" -) -install(FILES "${CMAKE_BINARY_DIR}/libopen-ocpp.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +if(${BUILD_SHARED_LIBRARY}) + set(LIB_NAME "open-ocpp") + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/deploy/libopen-ocpp.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/libopen-ocpp.pc" + ) + install(FILES "${CMAKE_BINARY_DIR}/libopen-ocpp.pc" DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif() if(${BUILD_STATIC_LIBRARY}) set(LIB_NAME "open-ocpp_static") diff --git a/CMakeLists_Options.txt b/CMakeLists_Options.txt index b6024cf3..3060238f 100644 --- a/CMakeLists_Options.txt +++ b/CMakeLists_Options.txt @@ -14,6 +14,9 @@ if(EXTERNAL_LOGGER) add_compile_definitions(EXTERNAL_LOGGER=1) endif() +# Shared library +option(BUILD_SHARED_LIBRARY "Build Open OCPP as a shared library" ON) + # Static library option(BUILD_STATIC_LIBRARY "Build Open OCPP as a static library" ON) @@ -26,6 +29,12 @@ option(BUILD_EXAMPLES "Build examples" # Build the libwebsocket library along with the Open OCPP library option(BUILD_LWS_LIBRARY "Build libwebsocket library" ON) +# Build the sqlite3 library along with the Open OCPP library +option(BUILD_SQLITE "Build sqlite3 library" ON) + +# Install the Doctest header +option(INSTALL_DOCTEST "Install doctest headers" ON) + # Use only the CrtAllocator in Rapidjson, not the MemoryPoolAllocator option(USE_CRT_ALLOC_FOR_RAPIDJSON "Use the CrtAllocator for Rapidjson instead of the MemoryPoolAllocator" OFF) if(USE_CRT_ALLOC_FOR_RAPIDJSON) diff --git a/examples/common/DefaultChargePointEventsHandler.cpp b/examples/common/DefaultChargePointEventsHandler.cpp index 7d8c1a1c..369039b0 100644 --- a/examples/common/DefaultChargePointEventsHandler.cpp +++ b/examples/common/DefaultChargePointEventsHandler.cpp @@ -169,15 +169,15 @@ bool DefaultChargePointEventsHandler::remoteStartTransactionRequested(unsigned i bool ret = false; cout << "Remote start transaction : " << connector_id << " - " << id_tag << endl; - if(connector_id > m_config.ocppConfig().numberOfConnectors() || connector_id == 0) + if (connector_id > m_config.ocppConfig().numberOfConnectors() || connector_id == 0) { - ret=false; + ret = false; } else { m_remote_start_pending[connector_id - 1u] = true; m_remote_start_id_tag[connector_id - 1u] = id_tag; - ret=true; + ret = true; } return ret; } diff --git a/examples/common/config/OcppConfig.cpp b/examples/common/config/OcppConfig.cpp index 86e16160..6c4db9be 100644 --- a/examples/common/config/OcppConfig.cpp +++ b/examples/common/config/OcppConfig.cpp @@ -207,8 +207,8 @@ ocpp::types::ConfigurationStatus OcppConfig::setConfiguration(const std::string& } } - if (ret != ConfigurationStatus::Rejected) - { + if (ret != ConfigurationStatus::Rejected) + { if ((it->second & PARAM_OCPP) != 0) { m_config.set(OCPP_PARAMS, key, value); @@ -225,7 +225,7 @@ ocpp::types::ConfigurationStatus OcppConfig::setConfiguration(const std::string& { ret = ConfigurationStatus::Accepted; } - } + } } else { diff --git a/examples/security_centralsystem/CentralSystemEventsHandler.cpp b/examples/security_centralsystem/CentralSystemEventsHandler.cpp index 7d2cb8b4..ef3ac4f6 100644 --- a/examples/security_centralsystem/CentralSystemEventsHandler.cpp +++ b/examples/security_centralsystem/CentralSystemEventsHandler.cpp @@ -25,6 +25,7 @@ SOFTWARE. #include "CentralSystemEventsHandler.h" #include "ChargePointDatabase.h" +#include #include #include #include @@ -99,7 +100,8 @@ bool CentralSystemEventsHandler::checkCredentials(const std::string& chargepoint { bool ret = false; - cout << "Check credentials for [" << chargepoint_id << "] : " << password << endl; + std::string hex_encoded_password = ocpp::helpers::toHexString(password); + cout << "Check credentials for [" << chargepoint_id << "] : " << hex_encoded_password << endl; // HTTP Basic Authentication is for Charge Points configured with Security Profile 1 or 2 only @@ -111,7 +113,7 @@ bool CentralSystemEventsHandler::checkCredentials(const std::string& chargepoint { if ((security_profile == 1u) || (security_profile == 2u)) { - ret = (password == authent_key); + ret = (hex_encoded_password == authent_key); } else { @@ -257,14 +259,18 @@ ocpp::types::RegistrationStatus CentralSystemEventsHandler::ChargePointRequestHa } else { - // Generate an authent key for the charge point : minimal 16 bytes, max : 20 bytes - std::stringstream ss_authent_key; - ss_authent_key << std::hex; - for (int i = 0; i < 5; i++) + // Generate an authent key for the charge point : minimal 8 bytes, max : 20 bytes + std::mt19937 rand_gen; + std::uniform_int_distribution rand_distrib; + std::random_device rd; + rand_gen.seed(rd()); + + std::array authent_key_bytes; + for (auto& val : authent_key_bytes) { - ss_authent_key << std::setfill('0') << std::setw(4) << std::rand(); + val = static_cast(rand_distrib(rand_gen)); } - m_authent_key = ss_authent_key.str(); + m_authent_key = ocpp::helpers::toHexString(authent_key_bytes); // Add the charge point to the database m_chargepoint_db.addChargePoint(this->proxy()->identifier(), serial_number, vendor, model, 0, m_authent_key); diff --git a/src/chargepoint/ChargePoint.cpp b/src/chargepoint/ChargePoint.cpp index 96515056..0aa05710 100644 --- a/src/chargepoint/ChargePoint.cpp +++ b/src/chargepoint/ChargePoint.cpp @@ -990,7 +990,7 @@ void ChargePoint::rcpMessageSent(const std::string& msg) void ChargePoint::configurationValueChanged(const std::string& key) { // Check configuration key - if (key == "AuthorizationKey") + if (key == "authorizationkey") { // Reconnect with new authorization key if (m_ocpp_config.securityProfile() != 3) @@ -1001,7 +1001,7 @@ void ChargePoint::configurationValueChanged(const std::string& key) m_security_manager.logSecurityEvent(SECEVT_RECONFIG_SECURITY_PARAMETER, "AuthorizationKey"); } - else if (key == "SecurityProfile") + else if (key == "securityprofile") { // Reconnect with new profile LOG_INFO << "SecurityProfile modified, reconnect with new security profile"; @@ -1164,8 +1164,10 @@ bool ChargePoint::doConnect() std::string authorization_key = m_ocpp_config.authorizationKey(); if (!authorization_key.empty() && (security_profile <= 2)) { - credentials.user = m_stack_config.chargePointIdentifier(); - credentials.password = authorization_key; + auto authentication_key = ocpp::helpers::fromHexString(authorization_key); + credentials.user = m_stack_config.chargePointIdentifier(); + credentials.password = std::string(reinterpret_cast(authentication_key.data()), authorization_key.size()); + credentials.password.resize(authentication_key.size()); } if (security_profile != 1) { diff --git a/src/chargepoint/config/ConfigManager.cpp b/src/chargepoint/config/ConfigManager.cpp index 1137c9a4..d55763e2 100644 --- a/src/chargepoint/config/ConfigManager.cpp +++ b/src/chargepoint/config/ConfigManager.cpp @@ -49,13 +49,15 @@ ConfigManager::~ConfigManager() { } /** @copydoc void registerCheckFunction(const std::string&, ConfigurationValueCheckFunc) */ void ConfigManager::registerCheckFunction(const std::string& key, ConfigurationValueCheckFunc func) { - m_specific_checks[key] = func; + auto lower_case_key = ocpp::helpers::tolower(key); + m_specific_checks[lower_case_key] = func; } /** @copydoc void IConfigManager::registerConfigChangedListener(const std::string&, IConfigChangedListener&) */ void ConfigManager::registerConfigChangedListener(const std::string& key, IConfigChangedListener& listener) { - m_listeners[key] = &listener; + auto lower_case_key = ocpp::helpers::tolower(key); + m_listeners[lower_case_key] = &listener; } /** @copydoc bool GenericMessageHandler::handleMessage(const RequestType& request, @@ -93,10 +95,11 @@ bool ConfigManager::handleMessage(const ocpp::messages::ChangeConfigurationReq& response.status = ConfigurationStatus::Accepted; // Specific check - auto it = m_specific_checks.find(request.key); + auto lower_case_key = ocpp::helpers::tolower(request.key); + auto it = m_specific_checks.find(lower_case_key); if (it != m_specific_checks.end()) { - response.status = it->second(request.key, request.value); + response.status = it->second(lower_case_key, request.value); } if (response.status == ConfigurationStatus::Accepted) { @@ -105,10 +108,10 @@ bool ConfigManager::handleMessage(const ocpp::messages::ChangeConfigurationReq& if (response.status == ConfigurationStatus::Accepted) { // Notify change - auto iter = m_listeners.find(request.key); + auto iter = m_listeners.find(lower_case_key); if (iter != m_listeners.end()) { - iter->second->configurationValueChanged(request.key); + iter->second->configurationValueChanged(lower_case_key); } } } diff --git a/src/chargepoint/security/SecurityManager.cpp b/src/chargepoint/security/SecurityManager.cpp index 8fbadf41..b481a539 100644 --- a/src/chargepoint/security/SecurityManager.cpp +++ b/src/chargepoint/security/SecurityManager.cpp @@ -669,15 +669,16 @@ bool SecurityManager::handleMessage(const ocpp::messages::InstallCertificateReq& ocpp::types::ConfigurationStatus SecurityManager::checkAuthorizationKeyParameter(const std::string& key, const std::string& value) { (void)key; - ConfigurationStatus ret = ConfigurationStatus::Accepted; + ConfigurationStatus ret = ConfigurationStatus::Rejected; - // Authorization key length for security profiles 1 and 2 must be between 32 and 40 bytes - unsigned int security_profile = m_ocpp_config.securityProfile(); - if ((security_profile == 1) || (security_profile == 2)) + // Authorization key length for security profiles 1 and 2 must be between 16 and 40 bytes + // and must be a valid hexadecimal representation + if ((value.size() >= 16u) && (value.size() <= 40u)) { - if ((value.size() < 32u) || (value.size() > 40u)) + auto key_bytes = ocpp::helpers::fromHexString(value); + if (key_bytes.size() == (value.size() / 2u)) { - ret = ConfigurationStatus::Rejected; + ret = ConfigurationStatus::Accepted; } } diff --git a/src/chargepoint/smartcharging/ProfileDatabase.cpp b/src/chargepoint/smartcharging/ProfileDatabase.cpp index 6301b579..a0224357 100644 --- a/src/chargepoint/smartcharging/ProfileDatabase.cpp +++ b/src/chargepoint/smartcharging/ProfileDatabase.cpp @@ -362,6 +362,7 @@ std::string ProfileDatabase::serialize(const ocpp::types::ChargingProfile& profi rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); + writer.SetMaxDecimalPlaces(1); // OCPP decimals have 1 digit precision profile_json.Accept(writer); profile_str = buffer.GetString(); return profile_str; diff --git a/src/chargepoint/smartcharging/SmartChargingManager.cpp b/src/chargepoint/smartcharging/SmartChargingManager.cpp index 0ca28601..e7c71fe2 100644 --- a/src/chargepoint/smartcharging/SmartChargingManager.cpp +++ b/src/chargepoint/smartcharging/SmartChargingManager.cpp @@ -303,7 +303,7 @@ bool SmartChargingManager::handleMessage(const ocpp::messages::SetChargingProfil } else { - ret = false; + ret = false; error_message = "Recurring profiles must have a start schedule and a duration"; } } diff --git a/src/messages/IMessageConverter.h b/src/messages/IMessageConverter.h index 07363963..0636aaa1 100644 --- a/src/messages/IMessageConverter.h +++ b/src/messages/IMessageConverter.h @@ -94,6 +94,17 @@ class IMessageConverter json.AddMember(rapidjson::StringRef(name), rapidjson::Value(value), *allocator); } + /** + * @brief Helper function to fill a floating point value in a JSON object + * @param json JSON object to fill + * @param field Name of the field to fill + * @param value Floating point value to fill + */ + void fill(rapidjson::Value& json, const char* name, const double value) + { + json.AddMember(rapidjson::StringRef(name), rapidjson::Value(value), *allocator); + } + /** * @brief Helper function to fill a string value in a JSON object * @param json JSON object to fill diff --git a/src/messages/MessagesValidator.h b/src/messages/MessagesValidator.h index acaeef9c..3d24e466 100644 --- a/src/messages/MessagesValidator.h +++ b/src/messages/MessagesValidator.h @@ -19,7 +19,7 @@ along with OpenOCPP. If not, see . #ifndef OPENOCPP_MESSAGESVALIDATOR_H #define OPENOCPP_MESSAGESVALIDATOR_H -#include +#include "JsonValidator.h" #include #include diff --git a/src/messages/StatusNotification.cpp b/src/messages/StatusNotification.cpp index b0b011d8..ca9f41bb 100644 --- a/src/messages/StatusNotification.cpp +++ b/src/messages/StatusNotification.cpp @@ -71,8 +71,8 @@ bool StatusNotificationReqConverter::fromJson(const rapidjson::Value& json, extract(json, "info", data.info); data.status = ChargePointStatusHelper.fromString(json["status"].GetString()); ret = ret && extract(json, "timestamp", data.timestamp, error_message); - extract(json, "info", data.vendorId); - extract(json, "info", data.vendorErrorCode); + extract(json, "vendorId", data.vendorId); + extract(json, "vendorErrorCode", data.vendorErrorCode); if (!ret) { error_code = ocpp::rpc::IRpc::RPC_ERROR_TYPE_CONSTRAINT_VIOLATION; @@ -87,12 +87,12 @@ bool StatusNotificationReqConverter::toJson(const StatusNotificationReq& data, r fill(json, "errorCode", ChargePointErrorCodeHelper.toString(data.errorCode)); fill(json, "status", ChargePointStatusHelper.toString(data.status)); fill(json, "timestamp", data.timestamp); - if (data.errorCode != ChargePointErrorCode::NoError) - { + if (data.info.isSet()) fill(json, "info", data.info); + if (data.vendorId.isSet()) fill(json, "vendorId", data.vendorId); + if (data.vendorErrorCode.isSet()) fill(json, "vendorErrorCode", data.vendorErrorCode); - } return true; } diff --git a/src/rpc/RpcBase.cpp b/src/rpc/RpcBase.cpp index 44569edb..71955410 100644 --- a/src/rpc/RpcBase.cpp +++ b/src/rpc/RpcBase.cpp @@ -75,6 +75,7 @@ bool RpcBase::call(const std::string& action, // Serialize message rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); + writer.SetMaxDecimalPlaces(1); // OCPP decimals have 1 digit precision payload.Accept(writer); std::stringstream serialized_message; @@ -186,6 +187,7 @@ void RpcBase::processIncomingRequest(std::shared_ptr& rpc_message) // Serialize message rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); + writer.SetMaxDecimalPlaces(1); // OCPP decimals have 1 digit precision response.Accept(writer); std::stringstream serialized_message; diff --git a/src/tools/helpers/StringHelpers.cpp b/src/tools/helpers/StringHelpers.cpp index fa53d420..6b89aa34 100644 --- a/src/tools/helpers/StringHelpers.cpp +++ b/src/tools/helpers/StringHelpers.cpp @@ -18,6 +18,10 @@ along with OpenOCPP. If not, see . #include "StringHelpers.h" +#include +#include +#include + namespace ocpp { namespace helpers @@ -26,6 +30,14 @@ namespace helpers /** @brief Space */ const std::string SPACE_STRING = " "; +/** @brief Helper function to convert a string to lowercase */ +std::string tolower(const std::string& str) +{ + std::string ret = str; + std::transform(ret.begin(), ret.end(), ret.begin(), [](unsigned char c) { return std::tolower(c); }); + return ret; +} + /** @brief Helper function to trim a string */ std::string& trim(std::string& str, const std::string& chars) { @@ -114,5 +126,50 @@ bool endsWith(const std::string& str, const std::string& substr) return ret; } +/** @brief Helper function to convert a buffer to an hexadecimal string representation */ +std::string toHexString(const void* buffer, size_t size) +{ + std::stringstream ss; + const uint8_t* data = reinterpret_cast(buffer); + if (data) + { + ss << std::hex; + for (size_t i = 0; i < size; i++) + { + ss << std::setw(2) << std::setfill('0') << static_cast(data[i]) << ""; + } + } + return ss.str(); +} + +/** @brief Helper function to convert an hexadecimal string representation into an array of bytes */ +std::vector fromHexString(const std::string& hex_string) +{ + std::vector ret; + if ((hex_string.size() & 1) == 0) + { + try + { + for (size_t i = 0; i < hex_string.size(); i += 2u) + { + std::string ss = hex_string.substr(i, 2u); + for (const auto& c : ss) + { + if (!((c >= '0') && (c <= '9')) && !((c >= 'a') && (c <= 'f')) && !((c >= 'A') && (c <= 'F'))) + { + throw std::out_of_range(ss); + } + } + ret.push_back(static_cast(std::stoul(ss, nullptr, 16))); + } + } + catch (...) + { + ret.clear(); + } + } + return ret; +} + } // namespace helpers } // namespace ocpp diff --git a/src/tools/helpers/StringHelpers.h b/src/tools/helpers/StringHelpers.h index 0ef88592..225e475f 100644 --- a/src/tools/helpers/StringHelpers.h +++ b/src/tools/helpers/StringHelpers.h @@ -19,8 +19,10 @@ along with OpenOCPP. If not, see . #ifndef OPENOCPP_STRING_H #define OPENOCPP_STRING_H +#include #include #include + namespace ocpp { namespace helpers @@ -29,6 +31,14 @@ namespace helpers /** @brief Space */ extern const std::string SPACE_STRING; +/** + * @brief Helper function to convert a string to lowercase + * /!\ Works only on ASCII strings /!\ + * @param str String to convert + * @return Reference to the converted string + */ +std::string tolower(const std::string& str); + /** * @brief Helper function to trim a string * @param str String to trim @@ -87,6 +97,32 @@ bool startsWith(const std::string& str, const std::string& substr); */ bool endsWith(const std::string& str, const std::string& substr); +/** + * @brief Helper function to convert a buffer to an hexadecimal string representation + * @param buffer Buffer to convert + * @param size Size of the buffer in bytes + * @return Buffer contents as an hexadecimal string + */ +std::string toHexString(const void* buffer, size_t size); + +/** + * @brief Helper function to convert a ContiguousContainer to an hexadecimal string representation + * @param cont container to convert + * @return Container contents as an hexadecimal string + */ +template +std::string toHexString(const ContiguousContainer& cont) +{ + return toHexString(&cont[0], cont.size() * sizeof(cont[0])); +} + +/** + * @brief Helper function to convert an hexadecimal string representation into an array of bytes + * @param hex_string Hexadecimal string to convert + * @return Corresponding array of bytes, empty if the input string is invalid + */ +std::vector fromHexString(const std::string& hex_string); + } // namespace helpers } // namespace ocpp diff --git a/src/tools/helpers/WorkerThreadPool.h b/src/tools/helpers/WorkerThreadPool.h index 8580623c..a2287c81 100644 --- a/src/tools/helpers/WorkerThreadPool.h +++ b/src/tools/helpers/WorkerThreadPool.h @@ -95,7 +95,10 @@ class Job : public JobBase } // Notify end of job - this->end = true; + { + std::lock_guard lock(this->end_of_job_mutex); + this->end = true; + } this->end_of_job_var.notify_all(); } @@ -132,7 +135,10 @@ class Job : public JobBase } // Notify end of job - this->end = true; + { + std::lock_guard lock(this->end_of_job_mutex); + this->end = true; + } this->end_of_job_var.notify_all(); } diff --git a/src/websockets/libwebsockets/LibWebsocketClient.cpp b/src/websockets/libwebsockets/LibWebsocketClient.cpp index f021356d..70074138 100644 --- a/src/websockets/libwebsockets/LibWebsocketClient.cpp +++ b/src/websockets/libwebsockets/LibWebsocketClient.cpp @@ -23,6 +23,29 @@ along with OpenOCPP. If not, see . #include #include +/** @brief Generate basic authent header with bytes password (may contain \0 char) */ +int lws_http_basic_auth_gen2(const char* user, const void* pw, size_t pwd_len, char* buf, size_t len) +{ + size_t n = strlen(user), m = pwd_len; + char b[128]; + + if (len < 6 + ((4 * (n + m + 1)) / 3) + 1) + return 1; + + memcpy(buf, "Basic ", 6); + + n = (unsigned int)lws_snprintf(b, sizeof(b), "%s:", user); + if ((n + pwd_len) >= sizeof(b) - 2) + return 2; + memcpy(&b[n], pw, pwd_len); + n += pwd_len; + + lws_b64_encode_string(b, (int)n, buf + 6, (int)len - 6); + buf[len - 1] = '\0'; + + return 0; +} + namespace ocpp { namespace websockets @@ -411,7 +434,11 @@ int LibWebsocketClient::eventCallback(struct lws* wsi, enum lws_callback_reasons if (client->m_credentials.user.empty()) break; - if (lws_http_basic_auth_gen(client->m_credentials.user.c_str(), client->m_credentials.password.c_str(), b, sizeof(b))) + if (lws_http_basic_auth_gen2(client->m_credentials.user.c_str(), + client->m_credentials.password.data(), + client->m_credentials.password.size(), + b, + sizeof(b))) break; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, (unsigned char*)b, (int)strlen(b), p, end)) return -1; diff --git a/src/websockets/libwebsockets/LibWebsocketClientPool.cpp b/src/websockets/libwebsockets/LibWebsocketClientPool.cpp index f9dbd9be..5b58e60f 100644 --- a/src/websockets/libwebsockets/LibWebsocketClientPool.cpp +++ b/src/websockets/libwebsockets/LibWebsocketClientPool.cpp @@ -22,6 +22,9 @@ along with OpenOCPP. If not, see . #include #include +/** @brief Generate basic authent header with bytes password (may contain \0 char) => implemented in LibWebsocketClient.cpp*/ +extern int lws_http_basic_auth_gen2(const char* user, const void* pw, size_t pwd_len, char* buf, size_t len); + namespace ocpp { namespace websockets @@ -599,7 +602,11 @@ int LibWebsocketClientPool::Client::eventCallback( if (client->m_credentials.user.empty()) break; - if (lws_http_basic_auth_gen(client->m_credentials.user.c_str(), client->m_credentials.password.c_str(), b, sizeof(b))) + if (lws_http_basic_auth_gen2(client->m_credentials.user.c_str(), + client->m_credentials.password.data(), + client->m_credentials.password.size(), + b, + sizeof(b))) break; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION, (unsigned char*)b, (int)strlen(b), p, end)) return -1; diff --git a/src/websockets/libwebsockets/LibWebsocketServer.cpp b/src/websockets/libwebsockets/LibWebsocketServer.cpp index 2efa8b29..f6815c10 100644 --- a/src/websockets/libwebsockets/LibWebsocketServer.cpp +++ b/src/websockets/libwebsockets/LibWebsocketServer.cpp @@ -383,7 +383,8 @@ int LibWebsocketServer::eventCallback(struct lws* wsi, enum lws_callback_reasons { // Check credentials std::string username(plain, static_cast(pcolon - plain)); - std::string password(pcolon + 1u); + std::string password(pcolon + 1u, m - (username.size() + 1u)); + password.resize(m - (username.size() + 1u)); authorized = server->m_listener->wsCheckCredentials(uri, username, password); } }