diff --git a/w3c-visserver-api/CMakeLists.txt b/w3c-visserver-api/CMakeLists.txt index e680223..cf411fe 100644 --- a/w3c-visserver-api/CMakeLists.txt +++ b/w3c-visserver-api/CMakeLists.txt @@ -34,7 +34,7 @@ add_compile_options(-std=c++11 -pthread -Wall -Wextra -Werror) if ("${ADDRESS_SAN}" STREQUAL "ON" AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_compile_options(-g -fsanitize=address -fno-omit-frame-pointer) - add_link_options(-g -fsanitize=address) + add_link_options(-g -fsanitize=address -ldl) endif() @@ -61,7 +61,7 @@ set(Boost_USE_STATIC_LIBS ON) include_directories(${Boost_INCLUDE_DIRS}) message(STATUS " boost includes ${Boost_INCLUDE_DIRS} ") -find_package(Boost 1.58.0 COMPONENTS system thread program_options REQUIRED) +find_package(Boost 1.64.0 COMPONENTS system thread program_options REQUIRED) target_link_libraries(simple-websocket-server INTERFACE ${Boost_LIBRARIES}) target_include_directories(simple-websocket-server INTERFACE ${Boost_INCLUDE_DIR}) @@ -114,6 +114,7 @@ if(UNIT_TEST) ${CMAKE_CURRENT_SOURCE_DIR}/src/subscriptionhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/signing.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/wsserver.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/BasicLogger.cpp # ${CMAKE_CURRENT_SOURCE_DIR}/unit-test/vssdatabase_test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/unit-test/w3cunittest.cpp ) diff --git a/w3c-visserver-api/include/BasicLogger.hpp b/w3c-visserver-api/include/BasicLogger.hpp new file mode 100644 index 0000000..8d1011d --- /dev/null +++ b/w3c-visserver-api/include/BasicLogger.hpp @@ -0,0 +1,44 @@ +/* + * ****************************************************************************** + * Copyright (c) 2019 Robert Bosch GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/index.php + * + * Contributors: + * Robert Bosch GmbH - initial API and functionality + * ***************************************************************************** + */ + + +#ifndef __LOGGER_H__ +#define __LOGGER_H__ + +#include "ILogger.hpp" + +#include + + +/** + * \class Logger + * \brief Implementation class of logging utility + * + * Logger shall provide standardized way to put logging information + * to standard output (stdout) + * + */ +class BasicLogger : public ILogger { + private: + std::mutex accessMutex; + const uint8_t logLevels; + + public: + BasicLogger(uint8_t logEventsEnabled); + ~BasicLogger(); + + void Log(LogLevel level, std::string logString); +}; + +#endif /* __LOGGER_H__ */ diff --git a/w3c-visserver-api/include/ILogger.hpp b/w3c-visserver-api/include/ILogger.hpp new file mode 100644 index 0000000..c6ecb9d --- /dev/null +++ b/w3c-visserver-api/include/ILogger.hpp @@ -0,0 +1,63 @@ +/* + * ****************************************************************************** + * Copyright (c) 2019 Robert Bosch GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/index.php + * + * Contributors: + * Robert Bosch GmbH - initial API and functionality + * ***************************************************************************** + */ + + +#ifndef __ILOGGER_H__ +#define __ILOGGER_H__ + +#include +#include + +/** + * \class LogLevel + * \brief Supported logging levels + * + * Enumeration shall be used by implementations of \ref ILogger class to define + * which events to log. + * As enumeration is bitwise compatible, implementations can allow for combining + * different log levels (e.g. INFO & ERROR, other levels shall be ignored) + */ +enum class LogLevel : uint8_t { + NONE = 0x0, //!< No logging allowed + VERBOSE = 0x1, //!< Used for logging verbose or debug information, not relevant in normal execution + INFO = 0x2, //!< Used for logging e.g. positive information relevant to execution + WARNING = 0x4, //!< Used for logging warning states and information that is not critical + ERROR = 0x8, //!< Used for logging any error or fail information + ALL = 0xF //!< Used for selecting all log levels +}; + + +/** + * \class ILogger + * \brief Interface definition for logging utility + * + * Interface for logger allows to easily add support for logging through different + * means or requirements (e.g. resource scarce platforms, socket, serial, ...) + * + */ +class ILogger { + public: + virtual ~ILogger() {} + + /** + * \brief Log message of specified notification level + * + * \param[in] Level of importance of log message + * \param[in] Log message + */ + virtual void Log(LogLevel, std::string) = 0; + +}; + +#endif /* __ILOGGER_H__ */ diff --git a/w3c-visserver-api/include/authenticator.hpp b/w3c-visserver-api/include/authenticator.hpp index b249d6c..1c3b8b3 100644 --- a/w3c-visserver-api/include/authenticator.hpp +++ b/w3c-visserver-api/include/authenticator.hpp @@ -14,21 +14,25 @@ #ifndef __AUTHENTICATOR_H__ #define __AUTHENTICATOR_H__ +#include #include using namespace std; class wschannel; class vssdatabase; +class ILogger; class authenticator { private: string pubkey = "secret"; string algorithm = "RS256"; + std::shared_ptr logger; + int validateToken(wschannel& channel, string authToken); public: - authenticator(string secretkey, string algorithm); + authenticator(std::shared_ptr loggerUtil, string secretkey, string algorithm); int validate(wschannel &channel, vssdatabase *database, string authToken); diff --git a/w3c-visserver-api/include/permmclient.hpp b/w3c-visserver-api/include/permmclient.hpp index 45a6e56..eed0631 100644 --- a/w3c-visserver-api/include/permmclient.hpp +++ b/w3c-visserver-api/include/permmclient.hpp @@ -16,11 +16,14 @@ #define __PERMMCLIENT_H__ #include +#include using namespace std; using namespace jsoncons; -json getPermToken(string clientName, string clientSecret); +class ILogger; + +json getPermToken(std::shared_ptr logger, string clientName, string clientSecret); diff --git a/w3c-visserver-api/include/signing.hpp b/w3c-visserver-api/include/signing.hpp index d2eacce..479f139 100644 --- a/w3c-visserver-api/include/signing.hpp +++ b/w3c-visserver-api/include/signing.hpp @@ -20,18 +20,23 @@ #include #include +#include + using namespace std; using namespace jsoncons; using namespace jwt; +class ILogger; + class signing { private: + std::shared_ptr logger; string key = ""; string pubkey = ""; string algorithm = "RS256"; public: - signing(); + signing(std::shared_ptr loggerUtil); string getKey(string fileName); string getPublicKey(string fileName); string sign(json data); diff --git a/w3c-visserver-api/include/subscriptionhandler.hpp b/w3c-visserver-api/include/subscriptionhandler.hpp index f2e25e7..d7b7d67 100644 --- a/w3c-visserver-api/include/subscriptionhandler.hpp +++ b/w3c-visserver-api/include/subscriptionhandler.hpp @@ -20,6 +20,7 @@ #include "visconf.hpp" #include #include +#include #include @@ -28,6 +29,7 @@ class authenticator; class vssdatabase; class wschannel; class wsserver; +class ILogger; // Subscription ID: Client ID typedef std::unordered_map subscriptions_t; @@ -37,6 +39,7 @@ typedef std::string uuid_t; class subscriptionhandler { private: + std::shared_ptr logger; std::unordered_map subscribeHandle; wsserver* server; authenticator* validator; @@ -47,7 +50,8 @@ class subscriptionhandler { std::queue> buffer; public: - subscriptionhandler(wsserver* wserver, + subscriptionhandler(std::shared_ptr loggerUtil, + wsserver* wserver, authenticator* authenticate, accesschecker* checkAccess); ~subscriptionhandler(); diff --git a/w3c-visserver-api/include/vsscommandprocessor.hpp b/w3c-visserver-api/include/vsscommandprocessor.hpp index eeaf5a6..fb492eb 100644 --- a/w3c-visserver-api/include/vsscommandprocessor.hpp +++ b/w3c-visserver-api/include/vsscommandprocessor.hpp @@ -15,6 +15,7 @@ #define __VSSCOMMANDPROCESSOR_H__ #include +#include #include @@ -23,9 +24,11 @@ class subscriptionhandler; class authenticator; class accesschecker; class wschannel; +class ILogger; class vsscommandprocessor { private: + std::shared_ptr logger; vssdatabase* database = NULL; subscriptionhandler* subHandler = NULL; authenticator* tokenValidator = NULL; @@ -48,7 +51,9 @@ class vsscommandprocessor { public: - vsscommandprocessor(vssdatabase* database, authenticator* vdator, + vsscommandprocessor(std::shared_ptr loggerUtil, + vssdatabase* database, + authenticator* vdator, subscriptionhandler* subhandler); ~vsscommandprocessor(); std::string processQuery(std::string req_json, wschannel& channel); diff --git a/w3c-visserver-api/include/vssdatabase.hpp b/w3c-visserver-api/include/vssdatabase.hpp index 24ca0a5..beb7f34 100644 --- a/w3c-visserver-api/include/vssdatabase.hpp +++ b/w3c-visserver-api/include/vssdatabase.hpp @@ -17,12 +17,14 @@ #include #include #include +#include #include class subscriptionhandler; class accesschecker; class wschannel; +class ILogger; class vssdatabase { friend class subscriptionhandler; @@ -32,6 +34,7 @@ class vssdatabase { #endif private: + std::shared_ptr logger; std::mutex rwMutex; jsoncons::json data_tree; jsoncons::json meta_tree; @@ -45,7 +48,8 @@ class vssdatabase { void checkSetPermission(wschannel& channel, jsoncons::json valueJson); public: - vssdatabase(subscriptionhandler* subHandle, + vssdatabase(std::shared_ptr loggerUtil, + subscriptionhandler* subHandle, accesschecker* accValidator); ~vssdatabase(); void initJsonTree(std::string fileName); diff --git a/w3c-visserver-api/include/wsserver.hpp b/w3c-visserver-api/include/wsserver.hpp index 3475216..5ac5a40 100644 --- a/w3c-visserver-api/include/wsserver.hpp +++ b/w3c-visserver-api/include/wsserver.hpp @@ -17,17 +17,20 @@ #include "server_wss.hpp" + class vsscommandprocessor; class vsscommandprocessor; class subscriptionhandler; class authenticator; class vssdatabase; class accesschecker; +class ILogger; class wsserver { private: SimpleWeb::SocketServer *secureServer_; SimpleWeb::SocketServer *insecureServer_; + std::shared_ptr logger; bool isSecure_; std::string configFileName_; @@ -38,7 +41,7 @@ class wsserver { vssdatabase* database; accesschecker* accessCheck; - wsserver(int port, std::string configFileName, bool secure); + wsserver(std::shared_ptr loggerUtil, int port, std::string configFileName, bool secure); ~wsserver(); void startServer(std::string endpointName); void sendToConnection(uint32_t connID, std::string message); diff --git a/w3c-visserver-api/src/BasicLogger.cpp b/w3c-visserver-api/src/BasicLogger.cpp new file mode 100644 index 0000000..5919fd4 --- /dev/null +++ b/w3c-visserver-api/src/BasicLogger.cpp @@ -0,0 +1,63 @@ +/* + * ****************************************************************************** + * Copyright (c) 2019 Robert Bosch GmbH. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/index.php + * + * Contributors: + * Robert Bosch GmbH - initial API and functionality + * ***************************************************************************** + */ + +#include "BasicLogger.hpp" + +#include + + +using namespace std; + +namespace { + std::string GetLevelString(LogLevel level) { + std::string retStr; + switch (level) { + case LogLevel::VERBOSE: + retStr = "VERBOSE: "; + break; + case LogLevel::INFO: + retStr = "INFO: "; + break; + case LogLevel::WARNING: + retStr = "WARNING: "; + break; + case LogLevel::ERROR: + retStr = "ERROR: "; + break; + default: + retStr = "UNKNOWN: "; + break; + } + return retStr; + } +} + + +BasicLogger::BasicLogger(uint8_t logEventsEnabled) : logLevels(logEventsEnabled) { + cout << "Log START" << endl; +} + + +BasicLogger::~BasicLogger() { + cout << "Log END" << endl; +} + +void BasicLogger::Log(LogLevel level, std::string logString) { + std::lock_guard guard(accessMutex); + + /* log only if level in supported */ + if (static_cast(level) & logLevels) { + cout << GetLevelString(level) + logString << endl; + } +} diff --git a/w3c-visserver-api/src/authenticator.cpp b/w3c-visserver-api/src/authenticator.cpp index 8d0b52c..bdec023 100644 --- a/w3c-visserver-api/src/authenticator.cpp +++ b/w3c-visserver-api/src/authenticator.cpp @@ -12,9 +12,11 @@ * ***************************************************************************** */ #include "authenticator.hpp" +#include "ILogger.hpp" #include #include #include +#include #include #include @@ -26,17 +28,14 @@ using namespace std; // using jsoncons; using jsoncons::json; -string getPublicKeyFromFile(string fileName) { - std::ifstream fileStream(fileName); - std::string key((std::istreambuf_iterator(fileStream)), - (std::istreambuf_iterator())); +namespace { + string getPublicKeyFromFile(string fileName) { + std::ifstream fileStream(fileName); + std::string key((std::istreambuf_iterator(fileStream)), + (std::istreambuf_iterator())); - return key; -} - -authenticator::authenticator(string secretkey, string algo) { - algorithm = algo; - pubkey = secretkey; + return key; + } } @@ -50,20 +49,19 @@ void authenticator::updatePubKey(string key) { int authenticator::validateToken(wschannel& channel, string authToken) { auto decoded = jwt::decode(authToken); json claims; + (void) channel; for (auto& e : decoded.get_payload_claims()) { - std::cout << e.first << " = " << e.second.to_json() << std::endl; + logger->Log(LogLevel::INFO, e.first + " = " + e.second.as_string()); claims[e.first] = e.second.to_json().to_str(); } auto verifier = jwt::verify().allow_algorithm( jwt::algorithm::rs256(pubkey, "", "", "")); - try { verifier.verify(decoded); } catch (const std::runtime_error& e) { - cout << "authenticator::validate: " << e.what() - << " Exception occured while authentication. Token is not valid!" - << endl; + logger->Log(LogLevel::ERROR, "authenticator::validate: " + string(e.what()) + + " Exception occured while authentication. Token is not valid!"); return -1; } @@ -73,6 +71,12 @@ int authenticator::validateToken(wschannel& channel, string authToken) { return ttl; } +authenticator::authenticator(std::shared_ptr loggerUtil, string secretkey, string algo) { + logger = loggerUtil; + algorithm = algo; + pubkey = secretkey; +} + // validates the token against expiry date/time. should be extended to check // some other claims. int authenticator::validate(wschannel& channel, vssdatabase* db, @@ -109,7 +113,7 @@ void authenticator::resolvePermissions(wschannel& channel, auto decoded = jwt::decode(authToken); json claims; for (auto& e : decoded.get_payload_claims()) { - std::cout << e.first << " = " << e.second.to_json() << std::endl; + logger->Log(LogLevel::INFO, string(e.first) + " = " + e.second.to_json().to_str()); stringstream value; value << e.second.to_json(); claims[e.first] = json::parse(value.str()); diff --git a/w3c-visserver-api/src/main.cpp b/w3c-visserver-api/src/main.cpp index 688848b..1023398 100644 --- a/w3c-visserver-api/src/main.cpp +++ b/w3c-visserver-api/src/main.cpp @@ -23,6 +23,9 @@ #include "vssdatabase.hpp" #include "exception.hpp" +#include "BasicLogger.hpp" + + using namespace std; using namespace boost; using namespace jsoncons; @@ -247,10 +250,6 @@ int main(int argc, const char *argv[]) { auto port = variables["port"].as(); auto secure = !variables.count("insecure"); auto vss_filename = variables["vss"].as(); - wsserver server(port, vss_filename, secure); - database = server.start(); - - // Start D-Bus backend connection. guint owner_id; @@ -272,11 +271,20 @@ int main(int argc, const char *argv[]) { loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); - g_bus_unown_name (owner_id); - g_dbus_node_info_unref (introspection_data); + uint8_t logLevelsActive; +#ifdef DEBUG + logLevelsActive = static_cast(LogLevel::ALL); +#else + logLevelsActive = static_cast(LogLevel::INFO & LogLevel::WARNING & LogLevel::ERROR); +#endif + std::shared_ptr logger = std::make_shared(logLevelsActive); + + wsserver server(logger, port, vss_filename, secure); + server.start(); + } catch (const program_options::error &ex) { print_usage(argv[0], desc); cerr << ex.what() << std::endl; diff --git a/w3c-visserver-api/src/permmclient.cpp b/w3c-visserver-api/src/permmclient.cpp index f1d6517..1a66cac 100644 --- a/w3c-visserver-api/src/permmclient.cpp +++ b/w3c-visserver-api/src/permmclient.cpp @@ -22,12 +22,13 @@ #include "exception.hpp" #include "permmclient.hpp" +#include "ILogger.hpp" using namespace std; #define SERVER "/home/pratheek/socket/kuksa_w3c_perm_management" -json getPermToken(string clientName, string clientSecret) { +json getPermToken(std::shared_ptr logger, string clientName, string clientSecret) { // Open unix socket connection. struct sockaddr_un addr; @@ -35,7 +36,7 @@ json getPermToken(string clientName, string clientSecret) { if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { throw genException("Unable to create a unix socket"); - //cout <<"Unable to create a unix socket"<Log(LogLevel::ERROR, "Unable to create a unix socket"); } memset(&addr, 0, sizeof(addr)); @@ -45,7 +46,7 @@ json getPermToken(string clientName, string clientSecret) { if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { throw genException("Unable to connect to server"); - //cout <<"Unable to connect to server"<Log(LogLevel::ERROR, "Unable to connect to server"); } @@ -59,15 +60,15 @@ json getPermToken(string clientName, string clientSecret) { int length = request.length(); // Send and wait for response from the permmanagent daemon. if(write(fd, request.c_str(), length) != length) { - cout << "Request not sent completely" <Log(LogLevel::ERROR, "Request not sent completely"); } else { - cout << "Request sent " <Log(LogLevel::INFO, "Request sent "); } char response_buf[1024 * 10] = {0}; read(fd, response_buf, sizeof(response_buf)); - cout << "Response read from server "<Log(LogLevel::INFO, "Response read from server "); string response(response_buf); jsoncons::json respJson = jsoncons::json::parse(response); diff --git a/w3c-visserver-api/src/signing.cpp b/w3c-visserver-api/src/signing.cpp index ab7ef29..9881d65 100644 --- a/w3c-visserver-api/src/signing.cpp +++ b/w3c-visserver-api/src/signing.cpp @@ -14,13 +14,15 @@ #include "signing.hpp" +#include "ILogger.hpp" + #define PRIVATEFILENAME "signing.private.key" #define PUBLICFILENAME "signing.public.key" /** Constructor */ -signing::signing() { +signing::signing(std::shared_ptr loggerUtil) : logger(loggerUtil) { getKey(PRIVATEFILENAME); getPublicKey(PUBLICFILENAME); } @@ -104,7 +106,7 @@ string signing::decode(string signedData) { try { verify.verify(decoded_token); } catch (exception& e) { - cout << "Error while verfying JSON signing " << e.what() << endl; + logger->Log(LogLevel::ERROR, "Error while verifying JSON signing " + string(e.what())); return ""; } diff --git a/w3c-visserver-api/src/subscriptionhandler.cpp b/w3c-visserver-api/src/subscriptionhandler.cpp index a5ac714..c5d57e1 100644 --- a/w3c-visserver-api/src/subscriptionhandler.cpp +++ b/w3c-visserver-api/src/subscriptionhandler.cpp @@ -14,6 +14,7 @@ #include "subscriptionhandler.hpp" #include // usleep +#include #include @@ -23,15 +24,18 @@ #include "visconf.hpp" #include "vssdatabase.hpp" #include "wsserver.hpp" +#include "ILogger.hpp" using namespace std; // using namespace jsoncons; using namespace jsoncons::jsonpath; // using jsoncons::jsoncons::jsoncons::json; -subscriptionhandler::subscriptionhandler(wsserver* wserver, +subscriptionhandler::subscriptionhandler(std::shared_ptr loggerUtil, + wsserver* wserver, authenticator* authenticate, accesschecker* checkAcc) { + logger = loggerUtil; server = wserver; validator = authenticate; checkAccess = checkAcc; @@ -68,28 +72,26 @@ uint32_t subscriptionhandler::subscribe(wschannel& channel, jsoncons::json result = resArray[0]; string sigUUID = result["uuid"].as(); auto handle = subscribeHandle.find(sigUUID); -#ifdef DEBUG + if (handle != subscribeHandle.end()) { - cout << "subscriptionhandler::subscribe: Updating the previous subscribe " - "ID with a new one" - << endl; + logger->Log(LogLevel::VERBOSE, string("subscriptionhandler::subscribe: Updating the previous subscribe ") + + string("ID with a new one")); } -#endif + subscribeHandle[sigUUID][subId] = clientID; return subId; } else if (resArray.is_array()) { - cout << resArray.size() - << "subscriptionhandler::subscribe :signals found in path" << path - << ". Subscribe works for 1 signal at a time" << endl; + logger->Log(LogLevel::INFO, "subscriptionhandler::subscribe :signals found in path" + path + + "Array size: " + to_string(resArray.size()) + + ". Subscribe works for 1 signal at a time"); stringstream msg; msg << "signals found in path" << path << ". Subscribe works for 1 signal at a time"; throw noPathFoundonTree(msg.str()); } else { - cout << "subscriptionhandler::subscribe: some error occured while adding " - "subscription" - << endl; + logger->Log(LogLevel::ERROR, string("subscriptionhandler::subscribe: some error occurred while adding ") + + string("subscription")); stringstream msg; msg << "some error occured while adding subscription for path = " << path; throw genException(msg.str()); @@ -151,9 +153,9 @@ int subscriptionhandler::updateByPath(string path, json value) { void* subscriptionhandler::subThreadRunner() { // subscriptionhandler* handler = (subscriptionhandler*)instance; -#ifdef DEBUG - cout << "SubscribeThread: Started Subscription Thread!" << endl; -#endif + + logger->Log(LogLevel::VERBOSE, "SubscribeThread: Started Subscription Thread!"); + while (isThreadRunning()) { subMutex.lock(); if (buffer.size() > 0) { @@ -180,20 +182,20 @@ void* subscriptionhandler::subThreadRunner() { // sleep 10 ms usleep(10000); } - cout << "SubscribeThread: Subscription handler thread stopped running" - << endl; + logger->Log(LogLevel::INFO, "SubscribeThread: Subscription handler thread stopped running"); return NULL; } int subscriptionhandler::startThread() { subThread = thread(&subscriptionhandler::subThreadRunner, this); - // if (pthread_create(&subscription_thread, NULL, &subThread, this)) { - // cout << "subscriptionhandler::startThread: Error creating subscription " - // "handler thread" - // << endl; - // return 1; - // } + /* + if (pthread_create(&subscription_thread, NULL, &subThread, this)) { + logger->Log(LogLevel::ERROR, "subscriptionhandler::startThread: Error creating subscription " + + "handler thread"); + return 1; + } + */ threadRun = true; return 0; } diff --git a/w3c-visserver-api/src/vsscommandprocessor.cpp b/w3c-visserver-api/src/vsscommandprocessor.cpp index 64663d2..529b530 100644 --- a/w3c-visserver-api/src/vsscommandprocessor.cpp +++ b/w3c-visserver-api/src/vsscommandprocessor.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "permmclient.hpp" #include "exception.hpp" @@ -25,6 +26,7 @@ #include "vssdatabase.hpp" #include "accesschecker.hpp" #include "subscriptionhandler.hpp" +#include "ILogger.hpp" #ifdef JSON_SIGNING_ON #include "signing.hpp" @@ -111,8 +113,11 @@ string valueOutOfBoundsResponse(uint32_t request_id, const string action, } vsscommandprocessor::vsscommandprocessor( - vssdatabase *dbase, authenticator *vdator, + std::shared_ptr loggerUtil, + vssdatabase *dbase, + authenticator *vdator, subscriptionhandler *subhandler) { + logger = loggerUtil; database = dbase; tokenValidator = vdator; subHandler = subhandler; @@ -128,14 +133,12 @@ vsscommandprocessor::~vsscommandprocessor() { string vsscommandprocessor::processGet(wschannel &channel, uint32_t request_id, string path) { -#ifdef DEBUG - cout << "GET :: path received from client = " << path << endl; -#endif + logger->Log(LogLevel::VERBOSE, "GET :: path received from client = " + path); jsoncons::json res; try { res = database->getSignal(channel, path); } catch (noPermissionException &nopermission) { - cout << nopermission.what() << endl; + logger->Log(LogLevel::ERROR, string(nopermission.what())); return noAccessResponse(request_id, "get", nopermission.what()); } if (!res.has_key("value")) { @@ -153,15 +156,12 @@ string vsscommandprocessor::processGet(wschannel &channel, string vsscommandprocessor::processSet(wschannel &channel, uint32_t request_id, string path, jsoncons::json value) { -#ifdef DEBUG - cout << "vsscommandprocessor::processSet: path received from client" << path - << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processSet: path received from client" + path); try { database->setSignal(channel, path, value); } catch (genException &e) { - cout << e.what() << endl; + logger->Log(LogLevel::ERROR, string(e.what())); jsoncons::json root; jsoncons::json error; @@ -179,13 +179,13 @@ string vsscommandprocessor::processSet(wschannel &channel, ss << pretty_print(root); return ss.str(); } catch (noPathFoundonTree &e) { - cout << e.what() << endl; + logger->Log(LogLevel::ERROR, string(e.what())); return pathNotFoundResponse(request_id, "set", path); } catch (outOfBoundException &outofboundExp) { - cout << outofboundExp.what() << endl; + logger->Log(LogLevel::ERROR, string(outofboundExp.what())); return valueOutOfBoundsResponse(request_id, "set", outofboundExp.what()); } catch (noPermissionException &nopermission) { - cout << nopermission.what() << endl; + logger->Log(LogLevel::ERROR, string(nopermission.what())); return noAccessResponse(request_id, "set", nopermission.what()); } @@ -202,24 +202,21 @@ string vsscommandprocessor::processSet(wschannel &channel, string vsscommandprocessor::processSubscribe(wschannel &channel, uint32_t request_id, string path, uint32_t connectionID) { -#ifdef DEBUG - cout << "vsscommandprocessor::processSubscribe: path received from client " - "for subscription" - << path << endl; -#endif + logger->Log(LogLevel::VERBOSE, string("vsscommandprocessor::processSubscribe: path received from client ") + + string("for subscription")); uint32_t subId = -1; try { subId = subHandler->subscribe(channel, database, connectionID, path); } catch (noPathFoundonTree &noPathFound) { - cout << noPathFound.what() << endl; + logger->Log(LogLevel::ERROR, string(noPathFound.what())); return pathNotFoundResponse(request_id, "subscribe", path); } catch (genException &outofboundExp) { - cout << outofboundExp.what() << endl; + logger->Log(LogLevel::ERROR, string(outofboundExp.what())); return valueOutOfBoundsResponse(request_id, "subscribe", outofboundExp.what()); } catch (noPermissionException &nopermission) { - cout << nopermission.what() << endl; + logger->Log(LogLevel::ERROR, string(nopermission.what())); return noAccessResponse(request_id, "subscribe", nopermission.what()); } @@ -311,9 +308,9 @@ string vsscommandprocessor::processAuthorizeWithPermManager(wschannel &channel, jsoncons::json response; // Get Token from permission management daemon. try { - response = getPermToken(client, clientSecret); + response = getPermToken(logger, client, clientSecret); } catch (genException &exp) { - cout << exp.what() << endl; + logger->Log(LogLevel::ERROR, exp.what()); jsoncons::json result; jsoncons::json error; result["action"] = "kuksa-authorize"; @@ -335,7 +332,7 @@ string vsscommandprocessor::processAuthorizeWithPermManager(wschannel &channel, tokenValidator->updatePubKey(response["pubkey"].as()); ttl = tokenValidator->validate(channel, database, response["token"].as()); } catch (exception &e) { - cout << e.what() << endl; + logger->Log(LogLevel::ERROR, e.what()); ttl = -1; } } @@ -416,27 +413,24 @@ string vsscommandprocessor::processQuery(string req_json, if (action == "authorize") { string token = root["tokens"].as(); uint32_t request_id = root["requestId"].as(); -#ifdef DEBUG - cout << "vsscommandprocessor::processQuery: authorize query with token = " - << token << " with request id " << request_id << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: authorize query with token = " + + token + " with request id " + to_string(request_id)); + response = processAuthorize(channel, request_id, token); } else if (action == "unsubscribe") { uint32_t request_id = root["requestId"].as(); uint32_t subscribeID = root["subscriptionId"].as(); -#ifdef DEBUG - cout << "vsscommandprocessor::processQuery: unsubscribe query for sub " - "ID = " - << subscribeID << " with request id " << request_id << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: unsubscribe query for sub ID = " + + to_string(subscribeID) + " with request id " + to_string(request_id)); + response = processUnsubscribe(request_id, subscribeID); } else if ( action == "kuksa-authorize") { string clientID = root["clientid"].as(); string clientSecret = root["secret"].as(); uint32_t request_id = root["requestId"].as(); #ifdef DEBUG - cout << "vsscommandprocessor::processQuery: kuksa authorize query with clientID = " - << clientID << " with secret " << clientSecret << endl; + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: kuksa authorize query with clientID = " + + clientID + " with secret " + clientSecret); #endif response = processAuthorizeWithPermManager(channel, request_id, clientID, clientSecret); } else { @@ -444,10 +438,8 @@ string vsscommandprocessor::processQuery(string req_json, uint32_t request_id = root["requestId"].as(); if (action == "get") { -#ifdef DEBUG - cout << "vsscommandprocessor::processQuery: get query for " << path - << " with request id " << request_id << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: get query for " + path + + " with request id " + to_string(request_id)); response = processGet(channel, request_id, path); #ifdef JSON_SIGNING_ON @@ -455,28 +447,21 @@ string vsscommandprocessor::processQuery(string req_json, #endif } else if (action == "set") { jsoncons::json value = root["value"]; -#ifdef DEBUG - cout << "vsscommandprocessor::processQuery: set query for " << path - << " with request id " << request_id << " value " - << pretty_print(value) << endl; -#endif + + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: set query for " + path + + " with request id " + to_string(request_id) + " value " + value.as_string()); response = processSet(channel, request_id, path, value); } else if (action == "subscribe") { -#ifdef DEBUG - cout << "vsscommandprocessor::processQuery: subscribe query for " - << path << " with request id " << request_id << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: subscribe query for " + + path + " with request id " + to_string(request_id)); response = processSubscribe(channel, request_id, path, channel.getConnID()); } else if (action == "getMetadata") { -#ifdef DEBUG - cout << "vsscommandprocessor::processQuery: metadata query for " - << path << " with request id " << request_id << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vsscommandprocessor::processQuery: metadata query for " + + path + " with request id " + to_string(request_id)); response = processGetMetaData(request_id, path); } else { - cout << "vsscommandprocessor::processQuery: Unknown action " << action - << endl; + logger->Log(LogLevel::INFO, "vsscommandprocessor::processQuery: Unknown action " + action); } } } catch (jsoncons::json_parse_exception e) { diff --git a/w3c-visserver-api/src/vssdatabase.cpp b/w3c-visserver-api/src/vssdatabase.cpp index e6d2e52..2200041 100644 --- a/w3c-visserver-api/src/vssdatabase.cpp +++ b/w3c-visserver-api/src/vssdatabase.cpp @@ -17,6 +17,7 @@ #include #include "exception.hpp" #include "visconf.hpp" +#include "ILogger.hpp" #include @@ -26,9 +27,149 @@ using namespace std; using namespace jsoncons::jsonpath; +namespace { + // Check the value type and if the value is within the range + void checkTypeAndBound(std::shared_ptr logger, string value_type, jsoncons::json val) { + bool typeValid = false; + + if (value_type == "uint8") { + typeValid = true; + long double longDoubleVal = val.as(); + if (!((longDoubleVal <= numeric_limits::max()) && + (longDoubleVal >= numeric_limits::min()))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " << val.as() + << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + + } else if (value_type == "uint16") { + typeValid = true; + long double longDoubleVal = val.as(); + if (!((longDoubleVal <= numeric_limits::max()) && + (longDoubleVal >= numeric_limits::min()))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " << val.as() + << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + + } else if (value_type == "uint32") { + typeValid = true; + long double longDoubleVal = val.as(); + if (!((longDoubleVal <= numeric_limits::max()) && + (longDoubleVal >= numeric_limits::min()))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " << val.as() + << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + + } else if (value_type == "int8") { + typeValid = true; + long double longDoubleVal = val.as(); + if (!((longDoubleVal <= numeric_limits::max()) && + (longDoubleVal >= numeric_limits::min()))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " << val.as() + << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + } else if (value_type == "int16") { + typeValid = true; + long double longDoubleVal = val.as(); + if (!((longDoubleVal <= numeric_limits::max()) && + (longDoubleVal >= numeric_limits::min()))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " << val.as() + << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + + } else if (value_type == "int32") { + typeValid = true; + long double longDoubleVal = val.as(); + if (!((longDoubleVal <= numeric_limits::max()) && + (longDoubleVal >= numeric_limits::min()))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " << val.as() + << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + } else if (value_type == "float") { + typeValid = true; + long double longDoubleVal = val.as(); + float max = numeric_limits::max(); + float min = numeric_limits::lowest(); + if (!((longDoubleVal <= max) && (longDoubleVal >= min))) { + std::stringstream msg; + msg << "The type " << value_type << " with value '" << val.as() + << "' is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + } else if (value_type == "double") { + typeValid = true; + long double longDoubleVal = val.as(); + double max = numeric_limits::max(); + double min = numeric_limits::lowest(); + if (!((longDoubleVal <= max) && (longDoubleVal >= min))) { + std::stringstream msg; + msg << "The type " << value_type << " with value " + << val.as() << " is out of bound"; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg.str()); + + throw outOfBoundException(msg.str()); + } + + } else if (value_type == "boolean") { + typeValid = true; + } else if (value_type == "string") { + typeValid = true; + } + + if (!typeValid) { + string msg = "The type " + value_type + " is not supported "; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg); + + throw genException(msg); + } + } + + + // Utility method for setting values to JSON. + void setJsonValue(std::shared_ptr logger, + jsoncons::json& dest, + jsoncons::json& source, + string key) { + if (!source.has_key("type")) { + string msg = "Unknown type for signal found at " + key; + logger->Log(LogLevel::ERROR, "vssdatabase::setJsonValue : " + msg); + + throw genException(msg); + } + dest[key] = source["value"]; + } +} + // Constructor -vssdatabase::vssdatabase(subscriptionhandler* subHandle, +vssdatabase::vssdatabase(std::shared_ptr loggerUtil, + subscriptionhandler* subHandle, accesschecker* accValidator) { + logger = loggerUtil; subHandler = subHandle; accessValidator = accValidator; } @@ -41,15 +182,14 @@ void vssdatabase::initJsonTree(string fileName) { std::ifstream is(fileName); is >> data_tree; meta_tree = data_tree; -#ifdef DEBUG - cout << "vssdatabase::vssdatabase : VSS tree initialized using JSON file = " - << fileName << endl; -#endif + + logger->Log(LogLevel::VERBOSE, "vssdatabase::vssdatabase : VSS tree initialized using JSON file = " + + fileName); is.close(); } catch (exception const& e) { - cout << "Exception occured while initializing database/ tree structure. " - "Probably the init json file not found!" - << e.what() << endl; + logger->Log(LogLevel::ERROR, + "Exception occured while initializing database/ tree structure. Probably the init json file not found!" + + string(e.what())); throw e; } } @@ -124,14 +264,13 @@ string vssdatabase::getVSSSpecificPath(string path, bool& isBranch, isBranch = false; } else { isBranch = false; - cout << "vssdatabase::getVSSSpecificPath : Path " << format_path - << " is invalid or is an empty tag!" << endl; + logger->Log(LogLevel::ERROR, "vssdatabase::getVSSSpecificPath : Path " + + format_path + " is invalid or is an empty tag!"); return ""; } } catch (exception& e) { - cout << "vssdatabase::getVSSSpecificPath :Exception " - << "\"" << e.what() << "\"" - << " occured while querying JSON. Check Path!" << endl; + logger->Log(LogLevel::ERROR, "vssdatabase::getVSSSpecificPath :Exception \"" + + string(e.what()) + "\" occured while querying JSON. Check Path!"); isBranch = false; return ""; } @@ -214,9 +353,7 @@ jsoncons::json vssdatabase::getMetaData(string path) { if (jPath == "") { return NULL; } -#ifdef DEBUG - cout << "vssdatabase::getMetaData: VSS specific path =" << jPath << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vssdatabase::getMetaData: VSS specific path =" + jPath); vector tokens = getVSSTokens(jPath); int tokLength = tokens.size(); @@ -248,9 +385,8 @@ jsoncons::json vssdatabase::getMetaData(string path) { } } else { // handle exception. - cout << "vssdatabase::getMetaData : More than 1 Branch/ value found! " - "Path requested needs to be more refined" - << endl; + logger->Log(LogLevel::ERROR, string("vssdatabase::getMetaData : More than 1 Branch/ value found! ") + + string("Path requested needs to be more refined")); return NULL; } @@ -347,131 +483,6 @@ jsoncons::json vssdatabase::getPathForSet(string path, jsoncons::json values) { return setValues; } -// Check the value type and if the value is within the range -void checkTypeAndBound(string value_type, jsoncons::json val) { - bool typeValid = false; - - if (value_type == "uint8") { - typeValid = true; - long double longDoubleVal = val.as(); - if (!((longDoubleVal <= numeric_limits::max()) && - (longDoubleVal >= numeric_limits::min()))) { - cout << "vssdatabase::setSignal: The value passed " << val.as() - << "for type " << value_type << " is out of bound." << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " << val.as() - << " is out of bound"; - throw outOfBoundException(msg.str()); - } - - } else if (value_type == "uint16") { - typeValid = true; - long double longDoubleVal = val.as(); - if (!((longDoubleVal <= numeric_limits::max()) && - (longDoubleVal >= numeric_limits::min()))) { - cout << "vssdatabase::setSignal: The value passed " << val.as() - << "for type " << value_type << " is out of bound." << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " << val.as() - << " is out of bound"; - throw outOfBoundException(msg.str()); - } - - } else if (value_type == "uint32") { - typeValid = true; - long double longDoubleVal = val.as(); - if (!((longDoubleVal <= numeric_limits::max()) && - (longDoubleVal >= numeric_limits::min()))) { - cout << "vssdatabase::setSignal: The value passed " << val.as() - << " for type " << value_type << " is out of bound." << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " << val.as() - << " is out of bound"; - throw outOfBoundException(msg.str()); - } - - } else if (value_type == "int8") { - typeValid = true; - long double longDoubleVal = val.as(); - if (!((longDoubleVal <= numeric_limits::max()) && - (longDoubleVal >= numeric_limits::min()))) { - cout << "vssdatabase::setSignal: The value passed " << val.as() - << "for type " << value_type << " is out of bound." << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " << val.as() - << " is out of bound"; - throw outOfBoundException(msg.str()); - } - } else if (value_type == "int16") { - typeValid = true; - long double longDoubleVal = val.as(); - if (!((longDoubleVal <= numeric_limits::max()) && - (longDoubleVal >= numeric_limits::min()))) { - cout << "vssdatabase::setSignal: The value passed " << val.as() - << "for type " << value_type << " is out of bound." << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " << val.as() - << " is out of bound"; - throw outOfBoundException(msg.str()); - } - - } else if (value_type == "int32") { - typeValid = true; - long double longDoubleVal = val.as(); - if (!((longDoubleVal <= numeric_limits::max()) && - (longDoubleVal >= numeric_limits::min()))) { - cout << "vssdatabase::setSignal: The value passed " << val.as() - << "for type " << value_type << " is out of bound." << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " << val.as() - << " is out of bound"; - throw outOfBoundException(msg.str()); - } - } else if (value_type == "float") { - typeValid = true; - long double longDoubleVal = val.as(); - float max = numeric_limits::max(); - float min = numeric_limits::lowest(); - if (!((longDoubleVal <= max) && (longDoubleVal >= min))) { - cout << "vssdatabase::setSignal: The value passed " - << val.as() << " for type " << value_type - << " is out of bound." - << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value '" << val.as() - << "' is out of bound"; - throw outOfBoundException(msg.str()); - } - } else if (value_type == "double") { - typeValid = true; - long double longDoubleVal = val.as(); - double max = numeric_limits::max(); - double min = numeric_limits::lowest(); - if (!((longDoubleVal <= max) && (longDoubleVal >= min))) { - cout << "vssdatabase::setSignal: The value passed '" - << val.as() << "' for type " << value_type - << " is out of bound." - << endl; - std::stringstream msg; - msg << "The type " << value_type << " with value " - << val.as() << " is out of bound"; - throw outOfBoundException(msg.str()); - } - - } else if (value_type == "boolean") { - typeValid = true; - } else if (value_type == "string") { - typeValid = true; - } - - if (!typeValid) { - cout << "vssdatabase::setSignal: The type " << value_type - << " is either not supported " << endl; - string msg = "The type " + value_type + " is not supported "; - throw genException(msg); - } -} - void vssdatabase::checkSetPermission(wschannel& channel, jsoncons::json valueJson) { // check if all the paths have write access. bool haveAccess = accessValidator->checkPathWriteAccess(channel, valueJson); @@ -500,8 +511,8 @@ void vssdatabase::setSignal(wschannel& channel, string path, jsoncons::json item = setValues[i]; string jPath = item["path"].as(); #ifdef DEBUG - cout << "vssdatabase::setSignal: path found = " << jPath << endl; - cout << "value to set asstring = " << item["value"].as() << endl; + logger->Log(LogLevel::VERBOSE, "vssdatabase::setSignal: path found = " + jPath); + logger->Log(LogLevel::VERBOSE, "value to set asstring = " + item["value"].as()); #endif rwMutex.lock(); jsoncons::json resArray = json_query(data_tree, jPath); @@ -511,7 +522,7 @@ void vssdatabase::setSignal(wschannel& channel, string path, if (resJson.has_key("datatype")) { string value_type = resJson["datatype"].as(); json val = item["value"]; - checkTypeAndBound(value_type, val); + checkTypeAndBound(logger, value_type, val); resJson.insert_or_assign("value", val); @@ -519,8 +530,7 @@ void vssdatabase::setSignal(wschannel& channel, string path, json_replace(data_tree, jPath, resJson); rwMutex.unlock(); #ifdef DEBUG - cout << "vssdatabase::setSignal: new value set at path " << jPath - << endl; + logger->Log(LogLevel::VERBOSE, "vssdatabase::setSignal: new value set at path " + jPath); #endif string uuid = resJson["uuid"].as(); @@ -534,12 +544,10 @@ void vssdatabase::setSignal(wschannel& channel, string path, } } else if (resArray.is_array()) { - cout << "vssdatabase::setSignal : Path " << jPath << " has " - << resArray.size() << " signals, the path needs refinement" - << endl; stringstream msg; msg << "Path " << jPath << " has " << resArray.size() << " signals, the path needs refinement"; + logger->Log(LogLevel::INFO, "vssdatabase::setSignal : " + msg.str()); throw genException(msg.str()); } } @@ -549,7 +557,6 @@ void vssdatabase::setSignal(wschannel& channel, string path, } } - // Method for setting values to signals. void vssdatabase::setSignal(string path, jsoncons::json valueJson) { @@ -565,10 +572,10 @@ void vssdatabase::setSignal(string path, for (size_t i = 0; i < setValues.size(); i++) { jsoncons::json item = setValues[i]; string jPath = item["path"].as(); -#ifdef DEBUG - cout << "vssdatabase::setSignal: path found = " << jPath << endl; - cout << "value to set asstring = " << item["value"].as() << endl; -#endif + + logger->Log(LogLevel::VERBOSE, "vssdatabase::setSignal: path found = " + jPath + + "value to set asstring = " + item["value"].as()); + rwMutex.lock(); jsoncons::json resArray = json_query(data_tree, jPath); rwMutex.unlock(); @@ -578,17 +585,14 @@ void vssdatabase::setSignal(string path, if (resJson.has_key("datatype")) { string value_type = resJson["datatype"].as(); json val = item["value"]; - checkTypeAndBound(value_type, val); + checkTypeAndBound(logger, value_type, val); resJson.insert_or_assign("value", val); rwMutex.lock(); json_replace(data_tree, jPath, resJson); rwMutex.unlock(); -#ifdef DEBUG - cout << "vssdatabase::setSignal: new value set at path " << jPath - << endl; -#endif + logger->Log(LogLevel::VERBOSE, "vssdatabase::setSignal: new value set at path " + jPath); string uuid = resJson["uuid"].as(); @@ -602,33 +606,18 @@ void vssdatabase::setSignal(string path, } } else if (resArray.is_array()) { - cout << "vssdatabase::setSignal : Path " << jPath << " has " - << resArray.size() << " signals, the path needs refinement" - << endl; stringstream msg; - msg << "Path " << jPath << " has " << resArray.size() - << " signals, the path needs refinement"; + msg << "Path " << jPath << " has " << resArray.size() << " signals, the path needs refinement"; + logger->Log(LogLevel::WARNING, "vssdatabase::setSignal: " + msg.str()); + throw genException(msg.str()); } } } else { - string msg = "Exception occured while setting data for " + path; - throw genException(msg); - } -} - - - -// Utility method for setting values to JSON. -void setJsonValue(jsoncons::json& dest, jsoncons::json& source, string key) { - if (!source.has_key("type")) { - cout << "vssdatabase::setJsonValue : could not set value! type is not " - "present in source json!" - << endl; - string msg = "Unknown type for signal found at " + key; + string msg = "Exception occurred while setting data for " + path; + logger->Log(LogLevel::ERROR, "vssdatabase::setSignal: " + msg); throw genException(msg); } - dest[key] = source["value"]; } // Returns response JSON for get request. @@ -643,18 +632,13 @@ jsoncons::json vssdatabase::getSignal(class wschannel& channel, string path) { jsoncons::json answer; return answer; } -#ifdef DEBUG - cout << "vssdatabase::getSignal: " << pathsFound - << " signals found under path = " - << "\"" << path << "\"" << endl; -#endif + + logger->Log(LogLevel::VERBOSE, "vssdatabase::getSignal: " + to_string(pathsFound) + + " signals found under path = \"" + path + "\""); if (isBranch) { jsoncons::json answer; -#ifdef DEBUG - cout << " vssdatabase::getSignal :" - << "\"" << path << "\"" - << " is a Branch." << endl; -#endif + logger->Log(LogLevel::VERBOSE, " vssdatabase::getSignal : \"" + path + "\" is a Branch."); + if (pathsFound == 0) { throw noPathFoundonTree(path); } else { @@ -681,7 +665,7 @@ jsoncons::json vssdatabase::getSignal(class wschannel& channel, string path) { jPaths.pop_back(); jsoncons::json result = resArray[0]; if (result.has_key("value")) { - setJsonValue(value, result, getReadablePath(jPath)); + setJsonValue(logger, value, result, getReadablePath(jPath)); } else { value[getReadablePath(jPath)] = "---"; } @@ -704,7 +688,7 @@ jsoncons::json vssdatabase::getSignal(class wschannel& channel, string path) { answer["path"] = getReadablePath(jPath); jsoncons::json result = resArray[0]; if (result.has_key("value")) { - setJsonValue(answer, result, "value"); + setJsonValue(logger, answer, result, "value"); return answer; } else { answer["value"] = "---"; @@ -737,7 +721,7 @@ jsoncons::json vssdatabase::getSignal(class wschannel& channel, string path) { jPaths.pop_back(); jsoncons::json result = resArray[0]; if (result.has_key("value")) { - setJsonValue(value, result, getReadablePath(jPath)); + setJsonValue(logger, value, result, getReadablePath(jPath)); } else { value[getReadablePath(jPath)] = "---"; } diff --git a/w3c-visserver-api/src/wsserver.cpp b/w3c-visserver-api/src/wsserver.cpp index 0d43a1e..23c8118 100644 --- a/w3c-visserver-api/src/wsserver.cpp +++ b/w3c-visserver-api/src/wsserver.cpp @@ -13,6 +13,7 @@ */ #include "wsserver.hpp" +#include "ILogger.hpp" #include "accesschecker.hpp" #include "authenticator.hpp" #include "subscriptionhandler.hpp" @@ -20,6 +21,8 @@ #include "vsscommandprocessor.hpp" #include "vssdatabase.hpp" +#include + using namespace std; using WssServer = SimpleWeb::SocketServer; @@ -40,7 +43,8 @@ uint32_t generateConnID() { return retValueValue; } -wsserver::wsserver(int port, string configFileName, bool secure) { +wsserver::wsserver(std::shared_ptr loggerUtil, int port, string configFileName, bool secure) { + logger = loggerUtil; isSecure_ = secure; secureServer_ = nullptr; insecureServer_ = nullptr; @@ -54,11 +58,11 @@ wsserver::wsserver(int port, string configFileName, bool secure) { insecureServer_->config.port = port; } - tokenValidator = new authenticator("appstacle", "RS256"); + tokenValidator = new authenticator(logger, "appstacle", "RS256"); accessCheck = new accesschecker(tokenValidator); - subHandler = new subscriptionhandler(this, tokenValidator, accessCheck); - database = new vssdatabase(subHandler, accessCheck); - cmdProcessor = new vsscommandprocessor(database, tokenValidator, subHandler); + subHandler = new subscriptionhandler(logger, this, tokenValidator, accessCheck); + database = new vssdatabase(logger, subHandler, accessCheck); + cmdProcessor = new vsscommandprocessor(logger, database, tokenValidator, subHandler); wserver = this; } @@ -76,12 +80,15 @@ wsserver::~wsserver() { } } -static void onMessage(shared_ptr connection, +static void onMessage(std::weak_ptr wLogger, + shared_ptr connection, string message) { -#ifdef DEBUG - cout << "main::onMessage: Message received: \"" << message << "\" from " - << connection->remote_endpoint_address() << endl; -#endif + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::VERBOSE, "main::onMessage: Message received: \"" + + message + "\" from " + connection->remote_endpoint_address()); + } + string response = wserver->cmdProcessor->processQuery(message, connection->channel); @@ -90,12 +97,15 @@ static void onMessage(shared_ptr connection, connection->send(send_stream); } -static void onMessage(shared_ptr connection, +static void onMessage(std::weak_ptr wLogger, + shared_ptr connection, string message) { -#ifdef DEBUG - cout << "main::onMessage: Message received: \"" << message << "\" from " - << connection->remote_endpoint_address() << endl; -#endif + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::VERBOSE, "main::onMessage: Message received: \"" + + message + "\" from " + connection->remote_endpoint_address()); + } + string response = wserver->cmdProcessor->processQuery(message, connection->channel); @@ -106,95 +116,119 @@ static void onMessage(shared_ptr connection, void wsserver::startServer(string endpointName) { (void) endpointName; + + auto wLogger = std::weak_ptr(logger); + if (isSecure_) { auto &vssEndpoint = secureServer_->endpoint["^/vss/?$"]; - vssEndpoint.on_message = [](shared_ptr connection, + vssEndpoint.on_message = [wLogger](shared_ptr connection, shared_ptr message) { auto message_str = message->string(); - onMessage(connection, message_str); + onMessage(wLogger, connection, message_str); }; - vssEndpoint.on_open = [](shared_ptr connection) { + vssEndpoint.on_open = [wLogger](shared_ptr connection) { connection->channel.setConnID(generateConnID()); - cout << "wsserver: Opened connection " - << connection->remote_endpoint_address() << "conn ID " - << connection->channel.getConnID() << endl; + + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::INFO, std::string("wsserver: Opened connection " + + connection->remote_endpoint_address() + + "conn ID " + + to_string(connection->channel.getConnID()))); + } }; // See RFC 6455 7.4.1. for status codes - vssEndpoint.on_close = [](shared_ptr connection, + vssEndpoint.on_close = [wLogger](shared_ptr connection, int status, const string & /*reason*/) { uint32_t clientID = connection->channel.getConnID() / CLIENT_MASK; connections[clientID] = 0; // removeAllSubscriptions(clientID); - cout << "wsserver: Closed connection " - << connection->remote_endpoint_address() << " with status code " - << status << endl; + + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::INFO, "wsserver: Closed connection " + + connection->remote_endpoint_address() + + " with status code " + + to_string(status)); + } }; // See // http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference.html, // Error Codes for error code meanings - vssEndpoint.on_error = [](shared_ptr connection, - const SimpleWeb::error_code &ec) { + vssEndpoint.on_error = [wLogger](shared_ptr connection, + const SimpleWeb::error_code &ec) { uint32_t clientID = connection->channel.getConnID() / CLIENT_MASK; connections[clientID] = 0; // removeAllSubscriptions(clientID); - cout << "wsserver: Error in connection " - << connection->remote_endpoint_address() << " with con ID " - << connection->channel.getConnID() << ". " - << "Error: " << ec << ", error message: " << ec.message() << endl; + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::ERROR, "wsserver: Connection " + + connection->remote_endpoint_address() + " with con ID " + + to_string(connection->channel.getConnID()) + ". " + + "Error: " + to_string(ec.value()) + ", error message: " + ec.message()); + } }; - cout << "started Secure WS server" << endl; + logger->Log(LogLevel::INFO, "started Secure WS server"); secureServer_->start(); } else { auto &vssEndpoint = insecureServer_->endpoint["^/vss/?$"]; - vssEndpoint.on_message = [](shared_ptr connection, - shared_ptr message) { + vssEndpoint.on_message = [wLogger](shared_ptr connection, + shared_ptr message) { auto message_str = message->string(); - onMessage(connection, message_str); + onMessage(wLogger, connection, message_str); }; - vssEndpoint.on_open = [](shared_ptr connection) { + vssEndpoint.on_open = [wLogger](shared_ptr connection) { connection->channel.setConnID(generateConnID()); -#ifdef DEBUG - cout << "wsserver: Opened connection " - << connection->remote_endpoint_address() << "conn ID " - << connection->channel.getConnID() << endl; -#endif + + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::VERBOSE, "wsserver: Opened connection " + + connection->remote_endpoint_address() + "conn ID " + + to_string(connection->channel.getConnID())); + } }; // See RFC 6455 7.4.1. for status codes - vssEndpoint.on_close = [](shared_ptr connection, - int status, const string & /*reason*/) { + vssEndpoint.on_close = [wLogger](shared_ptr connection, + int status, const string & /*reason*/) { uint32_t clientID = connection->channel.getConnID() / CLIENT_MASK; connections[clientID] = 0; // removeAllSubscriptions(clientID); - cout << "wsserver: Closed connection " - << connection->remote_endpoint_address() << " with status code " - << status << endl; + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::INFO, "wsserver: Closed connection " + + connection->remote_endpoint_address() + " with status code " + + to_string(status)); + } }; // See // http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference.html, // Error Codes for error code meanings - vssEndpoint.on_error = [](shared_ptr connection, - const SimpleWeb::error_code &ec) { + vssEndpoint.on_error = [wLogger](shared_ptr connection, + const SimpleWeb::error_code &ec) { uint32_t clientID = connection->channel.getConnID() / CLIENT_MASK; connections[clientID] = 0; // removeAllSubscriptions(clientID); - cout << "wsserver: Error in connection " - << connection->remote_endpoint_address() << " with con ID " - << connection->channel.getConnID() << ". " - << "Error: " << ec << ", error message: " << ec.message() << endl; + auto logger = wLogger.lock(); + if (logger) { + logger->Log(LogLevel::ERROR, "wsserver: Connection " + + connection->remote_endpoint_address() + " with con ID " + + to_string(connection->channel.getConnID()) + ". " + + "Error: " + to_string(ec.value()) + ", error message: " + ec.message()); + } }; - cout << "started Insecure WS server" << endl; + logger->Log(LogLevel::INFO, "started Insecure WS server"); insecureServer_->start(); } } @@ -236,7 +270,7 @@ vssdatabase* wsserver::start() { /* create the web socket server thread. */ if (pthread_create(&startWSServer_thread, NULL, &startWSServer, NULL)) { - cout << "main: Error creating websocket server run thread" << endl; + logger->Log(LogLevel::ERROR, "main: Error creating websocket server run thread"); } return this->database; } diff --git a/w3c-visserver-api/unit-test/w3cunittest.cpp b/w3c-visserver-api/unit-test/w3cunittest.cpp index a55cc77..4db3c76 100755 --- a/w3c-visserver-api/unit-test/w3cunittest.cpp +++ b/w3c-visserver-api/unit-test/w3cunittest.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include "w3cunittest.hpp" #include "exception.hpp" @@ -28,6 +29,8 @@ #include "vssdatabase.hpp" #include "vsscommandprocessor.hpp" #include "wsserver.hpp" +#include "ILogger.hpp" +#include "BasicLogger.hpp" namespace utf = boost::unit_test; using namespace std; @@ -58,6 +61,7 @@ This has be signed using a local private/pub key pair using RS256 Algorithm (asy namespace bt = boost::unit_test; #define PORT 8090 +std::shared_ptr logger; wsserver* webSocket; subscriptionhandler* subhandler; authenticator* authhandler; @@ -69,13 +73,14 @@ vsscommandprocessor* commandProc; w3cunittest unittestObj(false); w3cunittest::w3cunittest(bool secure) { - webSocket = new wsserver(PORT, "vss_rel_2.0.json", secure); - authhandler = new authenticator("",""); + logger = std::make_shared(static_cast(LogLevel::ALL)); + webSocket = new wsserver(logger, PORT, "vss_rel_2.0.json", secure); + authhandler = new authenticator(logger, "",""); accesshandler = new accesschecker(authhandler); - subhandler = new subscriptionhandler(webSocket, authhandler, accesshandler); - database = new vssdatabase(subhandler, accesshandler); - commandProc = new vsscommandprocessor(database, authhandler , subhandler); - json_signer = new signing(); + subhandler = new subscriptionhandler(logger, webSocket, authhandler, accesshandler); + database = new vssdatabase(logger, subhandler, accesshandler); + commandProc = new vsscommandprocessor(logger, database, authhandler , subhandler); + json_signer = new signing(logger); database->initJsonTree("vss_rel_2.0.json"); } @@ -106,7 +111,7 @@ BOOST_AUTO_TEST_CASE(path_for_get_without_wildcard_simple) list paths = unittestObj.test_wrap_getPathForGet(test_path , isBranch); string result = paths.back(); - BOOST_TEST(paths.size() == 1); + BOOST_TEST(paths.size() == 1u); BOOST_TEST(result == "$['Vehicle']['children']['OBD']['children']['EngineSpeed']"); BOOST_TEST(isBranch == false); @@ -121,7 +126,7 @@ BOOST_AUTO_TEST_CASE(path_for_get_with_wildcard_simple) list paths = unittestObj.test_wrap_getPathForGet(test_path , isBranch); string result = paths.back(); - BOOST_TEST(paths.size() == 1); + BOOST_TEST(paths.size() == 1u); BOOST_TEST(result == "$['Vehicle']['children']['OBD']['children']['EngineSpeed']"); BOOST_TEST(isBranch == false); @@ -134,7 +139,7 @@ BOOST_AUTO_TEST_CASE(path_for_get_with_wildcard_multiple) bool isBranch = false; list paths = unittestObj.test_wrap_getPathForGet(test_path , isBranch); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); string result2 = paths.back(); paths.pop_back(); string result1 = paths.back(); @@ -153,7 +158,7 @@ BOOST_AUTO_TEST_CASE(test_get_branch) list paths = unittestObj.test_wrap_getPathForGet(test_path , isBranch); string result = paths.back(); - BOOST_TEST(paths.size() == 3); + BOOST_TEST(paths.size() == 3u); BOOST_TEST(isBranch == true); } @@ -166,7 +171,7 @@ BOOST_AUTO_TEST_CASE(test_get_branch_with_wildcard) list paths = unittestObj.test_wrap_getPathForGet(test_path , isBranch); string result = paths.back(); - BOOST_TEST(paths.size() == 10); + BOOST_TEST(paths.size() == 10u); BOOST_TEST(isBranch == true); } @@ -179,7 +184,7 @@ BOOST_AUTO_TEST_CASE(test_get_random) list paths = unittestObj.test_wrap_getPathForGet(test_path , isBranch); - BOOST_TEST(paths.size() == 0); + BOOST_TEST(paths.size() == 0u); BOOST_TEST(isBranch == false); } @@ -194,7 +199,7 @@ BOOST_AUTO_TEST_CASE(path_for_set_without_wildcard_simple) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value); - BOOST_TEST(paths.size() == 1); + BOOST_TEST(paths.size() == 1u); BOOST_TEST(paths[0]["path"].as_string() == "$['Vehicle']['children']['OBD']['children']['EngineSpeed']"); @@ -215,7 +220,7 @@ BOOST_AUTO_TEST_CASE(path_for_set_with_wildcard_simple) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == "$['Vehicle']['children']['OBD']['children']['EngineSpeed']"); BOOST_TEST(paths[1]["path"].as_string() == "$['Vehicle']['children']['OBD']['children']['Speed']"); @@ -237,7 +242,7 @@ BOOST_AUTO_TEST_CASE(path_for_set_with_wildcard_with_invalid_values) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == ""); BOOST_TEST(paths[1]["path"].as_string() == ""); @@ -258,7 +263,7 @@ BOOST_AUTO_TEST_CASE(path_for_set_with_wildcard_with_one_valid_value) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == "$['Vehicle']['children']['OBD']['children']['EngineSpeed']"); BOOST_TEST(paths[1]["path"].as_string() == ""); @@ -279,7 +284,7 @@ BOOST_AUTO_TEST_CASE(path_for_set_with_wildcard_with_invalid_path_valid_values) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == ""); BOOST_TEST(paths[1]["path"].as_string() == ""); @@ -316,7 +321,7 @@ BOOST_AUTO_TEST_CASE(test_set_value_on_branch_with_valid_values) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == "$['Vehicle']['children']['Cabin']['children']['HVAC']['children']['Row2']['children']['Left']['children']['Temperature']"); BOOST_TEST(paths[1]["path"].as_string() == "$['Vehicle']['children']['Cabin']['children']['HVAC']['children']['Row2']['children']['Right']['children']['Temperature']"); @@ -337,7 +342,7 @@ BOOST_AUTO_TEST_CASE(test_set_value_on_branch_with_invalid_values) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == ""); BOOST_TEST(paths[1]["path"].as_string() == ""); @@ -358,7 +363,7 @@ BOOST_AUTO_TEST_CASE(test_set_value_on_branch_with_one_invalid_value) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value_array); - BOOST_TEST(paths.size() == 2); + BOOST_TEST(paths.size() == 2u); BOOST_TEST(paths[0]["path"].as_string() == "$['Vehicle']['children']['Cabin']['children']['HVAC']['children']['Row2']['children']['Left']['children']['Temperature']"); BOOST_TEST(paths[1]["path"].as_string() == ""); @@ -982,7 +987,7 @@ BOOST_AUTO_TEST_CASE(test_set_random) json paths = unittestObj.test_wrap_getPathForSet(test_path , test_value); - BOOST_TEST(paths.size() == 1); + BOOST_TEST(paths.size() == 1u); BOOST_TEST(paths[0]["path"].as_string() == ""); }