From 28e5f90002c1ec4d73225c9a09914d38c8f48f59 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 19 Oct 2019 15:33:05 +0200 Subject: [PATCH 01/17] add other to areas --- src/ebusd/main.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index 1da71025..5fa2d78d 100755 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -223,11 +223,12 @@ static const struct argp_option argpoptions[] = { {"updatecheck", O_UPDCHK, "MODE", 0, "Set automatic update check to MODE (on|off) [on]", 0 }, {nullptr, 0, nullptr, 0, "Log options:", 5 }, - {"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon, empty string for using syslog) [" PACKAGE_LOGFILE "]", 0 }, + {"logfile", 'l', "FILE", 0, "Write log to FILE (only for daemon, empty string for using syslog) [" + PACKAGE_LOGFILE "]", 0 }, {"log", O_LOG, "AREAS LEVEL", 0, "Only write log for matching AREA(S) below or equal to LEVEL" " (alternative to --logareas/--logevel, may be used multiple times) [all notice]", 0 }, - {"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main|network|bus|update|all" - " [all]", 0 }, + {"logareas", O_LOGARE, "AREAS", 0, "Only write log for matching AREA(S): main|network|bus|update|other" + "|all [all]", 0 }, {"loglevel", O_LOGLEV, "LEVEL", 0, "Only write log below or equal to LEVEL: error|notice|info|debug" " [notice]", 0 }, From 67a42543f960b39bc4ff05c1144acd20832585e1 Mon Sep 17 00:00:00 2001 From: john30 Date: Sat, 19 Oct 2019 15:40:04 +0200 Subject: [PATCH 02/17] also check reconnect when loop reports connection loss --- src/ebusd/mqtthandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 986e6e46..34df71ab 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -778,7 +778,7 @@ bool MqttHandler::handleTraffic(bool allowReconnect) { #else ret = mosquitto_loop(m_mosquitto, -1); // waits up to 1 second for network traffic #endif - if (!m_connected && ret == MOSQ_ERR_NO_CONN && allowReconnect) { + if (!m_connected && (ret == MOSQ_ERR_NO_CONN || ret == MOSQ_ERR_CONN_LOST) && allowReconnect) { if (m_initialConnectFailed) { #if (LIBMOSQUITTO_MAJOR >= 1) ret = mosquitto_connect(m_mosquitto, g_host, g_port, 60); From 4cfdb4d97ce2874a2d2d2391dc721c2c468ff345 Mon Sep 17 00:00:00 2001 From: john30 Date: Thu, 24 Oct 2019 09:01:05 +0200 Subject: [PATCH 03/17] hide secrets from cmdline --- src/ebusd/mqtthandler.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 34df71ab..29b754e2 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -109,6 +109,13 @@ static const char* g_keypass = nullptr; //!< client key file password for TLS bool parseTopic(const string& topic, vector* strs, vector* fields); +static void replaceSecret(char *arg) { + int cnt = 0; + while (*arg) { + *arg++ = (cnt++<4 ? '*' : 0); + } +} + /** * The MQTT argument parsing function. * @param key the key from @a g_mqtt_argp_options. @@ -156,7 +163,8 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { argp_error(state, "invalid mqttpass"); return EINVAL; } - g_password = arg; + g_password = strdup(arg); + replaceSecret(arg); break; case O_TOPI: // --mqtttopic=ebusd @@ -237,7 +245,8 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { argp_error(state, "invalid mqttkeypass"); return EINVAL; } - g_keypass = arg; + g_keypass = strdup(arg); + replaceSecret(arg); break; #endif From ae91be0874852259f47904da309d3a95359334a9 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 08:17:22 +0100 Subject: [PATCH 04/17] simplified hiding secrets from cmdline (fixes #300) --- src/ebusd/mqtthandler.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 29b754e2..3f44c24f 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -109,11 +109,13 @@ static const char* g_keypass = nullptr; //!< client key file password for TLS bool parseTopic(const string& topic, vector* strs, vector* fields); -static void replaceSecret(char *arg) { +static char* replaceSecret(char *arg) { + char* ret = strdup(arg); int cnt = 0; - while (*arg) { - *arg++ = (cnt++<4 ? '*' : 0); + while (*arg && cnt++<256) { + *arg++ = ' '; } + return ret; } /** @@ -163,8 +165,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { argp_error(state, "invalid mqttpass"); return EINVAL; } - g_password = strdup(arg); - replaceSecret(arg); + g_password = replaceSecret(arg); break; case O_TOPI: // --mqtttopic=ebusd @@ -245,8 +246,7 @@ static error_t mqtt_parse_opt(int key, char *arg, struct argp_state *state) { argp_error(state, "invalid mqttkeypass"); return EINVAL; } - g_keypass = strdup(arg); - replaceSecret(arg); + g_keypass = replaceSecret(arg); break; #endif From 82d6a5b4a495223d86ea94bc6af61e4ea6942192 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 09:23:54 +0100 Subject: [PATCH 05/17] formatting --- src/ebusd/main.cpp | 2 +- src/ebusd/mqtthandler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 src/ebusd/main.cpp diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp old mode 100755 new mode 100644 index 5fa2d78d..d9bb90dc --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -702,7 +702,7 @@ void signalHandler(int sig) { switch (sig) { case SIGHUP: logNotice(lf_main, "SIGHUP received"); - if (!opt.foreground && opt.logFile && opt.logFile[0] != 0) { // for log file rotation + if (!opt.foreground && opt.logFile && opt.logFile[0] != 0) { // for log file rotation closeLogFile(); setLogFile(opt.logFile); } diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 3f44c24f..7460acc7 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -112,7 +112,7 @@ bool parseTopic(const string& topic, vector* strs, vector* field static char* replaceSecret(char *arg) { char* ret = strdup(arg); int cnt = 0; - while (*arg && cnt++<256) { + while (*arg && cnt++ < 256) { *arg++ = ' '; } return ret; From af77f4bc1e3fed4895278a78c527bb66ac21a7d9 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 09:27:22 +0100 Subject: [PATCH 06/17] add adjustable verbosity to listen command (fixes #163) --- src/ebusd/mainloop.cpp | 110 ++++++++++++++++++++++++++--------------- src/ebusd/mainloop.h | 8 +-- src/ebusd/network.cpp | 2 +- src/ebusd/network.h | 36 +++++++++----- 4 files changed, 101 insertions(+), 55 deletions(-) mode change 100755 => 100644 src/ebusd/mainloop.cpp mode change 100755 => 100644 src/ebusd/mainloop.h mode change 100755 => 100644 src/ebusd/network.cpp mode change 100755 => 100644 src/ebusd/network.h diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp old mode 100755 new mode 100644 index 9229278c..f39729a5 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -371,12 +371,12 @@ void MainLoop::run() { continue; } if (m_shutdown) { - netMessage->setResult("ERR: shutdown", "", cm_normal, now, true); + netMessage->setResult("ERR: shutdown", "", nullptr, now, true); break; } string request = netMessage->getRequest(); string user = netMessage->getUser(); - ClientMode mode = netMessage->getMode(&since); + ClientSettings settings = netMessage->getSettings(&since); if (!netMessage->isListeningMode()) { since = now; } @@ -384,9 +384,9 @@ void MainLoop::run() { bool connected = true; if (request.length() > 0) { logDebug(lf_main, ">>> %s", request.c_str()); - result_t result = decodeMessage(request, netMessage->isHttp(), &connected, &mode, &user, &reload, &ostream); + result_t result = decodeMessage(request, netMessage->isHttp(), &connected, &settings, &user, &reload, &ostream); if (!netMessage->isHttp() && (ostream.tellp() == 0 || result != RESULT_OK)) { - if (mode != cm_direct) { + if (settings.mode != cm_direct) { ostream.str(""); } ostream << getResultCode(result); @@ -399,25 +399,25 @@ void MainLoop::run() { if (ostream.tellp() == 0) { ostream << "\n"; // only for HTTP } else if (!netMessage->isHttp()) { - ostream << (mode == cm_direct ? "\n" : "\n\n"); + ostream << (settings.mode == cm_direct ? "\n" : "\n\n"); } } - if (mode == cm_listen) { + if (settings.mode == cm_listen) { string levels = getUserLevels(user); messages.clear(); m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now, true, &messages); for (const auto message : messages) { ostream << message->getCircuit() << " " << message->getName() << " = " << dec; - message->decodeLastData(false, nullptr, -1, 0, &ostream); + message->decodeLastData(false, nullptr, -1, settings.format, &ostream); ostream << endl; } - } else if (mode == cm_direct) { + } else if (settings.mode == cm_direct) { if (m_busHandler->isGrabEnabled()) { m_busHandler->formatGrabResult(false, false, &ostream, true, since, now); } } // send result to client - netMessage->setResult(ostream.str(), user, mode, now, !connected); + netMessage->setResult(ostream.str(), user, &settings, now, !connected); } } @@ -462,7 +462,7 @@ void MainLoop::notifyDeviceData(symbol_t symbol, bool received) { } } -result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, ClientMode* mode, +result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, ClientSettings* settings, string* user, bool* reload, ostringstream* ostream) { string token, previous; istringstream stream(data); @@ -520,8 +520,8 @@ result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connecte transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper); args.clear(); // empty args is used as command help indicator } - if (*mode == cm_direct) { - return executeDirect(args, mode, ostream); + if (settings->mode == cm_direct) { + return executeDirect(args, &settings->mode, ostream); } if (cmd.empty() && args.size() == 0) { return executeHelp(ostream); @@ -553,10 +553,10 @@ result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connecte return executeFind(args, getUserLevels(*user), ostream); } if (cmd == "L" || cmd == "LISTEN") { - return executeListen(args, mode, ostream); + return executeListen(args, settings, ostream); } if (cmd == "DIRECT") { - return executeDirect(args, mode, ostream); + return executeDirect(args, &settings->mode, ostream); } if (cmd == "S" || cmd == "STATE") { return executeState(args, ostream); @@ -652,7 +652,7 @@ result_t MainLoop::executeAuth(const vector& args, string* user, ostring result_t MainLoop::executeRead(const vector& args, const string& levels, ostringstream* ostream) { size_t argPos = 1; - bool hex = false, newDefinition = false, numeric = false, valueName = false; + bool hex = false, newDefinition = false; OutputFormat verbosity = 0; time_t maxAge = 5*60; string circuit, params; @@ -699,10 +699,9 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, } else if (args[argPos] == "-vvv" || args[argPos] == "-V") { verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; } else if (args[argPos] == "-n") { - numeric = true; + verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; } else if (args[argPos] == "-N") { - numeric = true; - valueName = true; + verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME; } else if (args[argPos] == "-c") { argPos++; if (argPos >= args.size()) { @@ -751,7 +750,7 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, } argPos++; } - if ((hex && (newDefinition || numeric || verbosity != 0 || !circuit.empty() || !params.empty() || dstAddress != SYN + if ((hex && (newDefinition || verbosity != 0 || !circuit.empty() || !params.empty() || dstAddress != SYN || pollPriority > 0 || args.size() < argPos + 1)) || (newDefinition && (hex || !circuit.empty() || pollPriority > 0 || args.size() != argPos + 1))) { argPos = 0; // print usage @@ -895,7 +894,6 @@ result_t MainLoop::executeRead(const vector& args, const string& levels, if (!newDefinition && message != nullptr && pollPriority > 0 && message->setPollPriority(pollPriority)) { m_messages->addPollMessage(false, message); } - verbosity |= valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0; bool allowCache = !newDefinition && srcAddress == SYN && dstAddress == SYN && maxAge > 0 && params.length() == 0; Message* cacheMessage = allowCache ? m_messages->find(circuit, name, levels, false, true) : nullptr; bool hasCache = cacheMessage != nullptr; @@ -1479,23 +1477,57 @@ result_t MainLoop::executeFind(const vector& args, const string& levels, return RESULT_OK; } -result_t MainLoop::executeListen(const vector& args, ClientMode* mode, ostringstream* ostream) { - if (args.size() == 1) { - if (*mode == cm_listen) { +result_t MainLoop::executeListen(const vector& args, ClientSettings* settings, ostringstream* ostream) { + size_t argPos = 1; + OutputFormat verbosity = 0; + while (args.size() > argPos && args[argPos][0] == '-') { + if (args[argPos] == "-v") { + switch (verbosity) { + case 0: + verbosity = OF_NAMES; + break; + case OF_NAMES: + verbosity |= OF_UNITS; + break; + case OF_NAMES|OF_UNITS: + verbosity |= OF_COMMENTS; + break; + } + } else if (args[argPos] == "-vv") { + verbosity |= OF_NAMES|OF_UNITS; + } else if (args[argPos] == "-vvv" || args[argPos] == "-V") { + verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; + } else if (args[argPos] == "-n") { + verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; + } else if (args[argPos] == "-N") { + verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME; + } else { + argPos = 0; // print usage + break; + } + argPos++; + } + if (argPos > 0 && args.size() == argPos) { + settings->format = verbosity; + if (settings->mode == cm_listen) { *ostream << "listen continued"; return RESULT_OK; } - *mode = cm_listen; + settings->mode = cm_listen; *ostream << "listen started"; return RESULT_OK; } - if (args.size() != 2 || args[1] != "stop") { - *ostream << "usage: listen [stop]\n" - " Listen for updates or stop it."; + if (argPos == 0 || args.size() != argPos + 1 || args[argPos] != "stop") { + *ostream << "usage: listen [-v|-V] [-n|-N] [stop]\n" + " Listen for updates or stop it.\n" + " -v increase verbosity (include names/units/comments)\n" + " -V be very verbose (include names, units, and comments)\n" + " -n use numeric value of value=name pairs\n" + " -N use numeric and named value of value=name pairs"; return RESULT_OK; } - *mode = cm_normal; + settings->mode = cm_normal; *ostream << "listen stopped"; return RESULT_OK; } @@ -1573,7 +1605,6 @@ result_t MainLoop::executeDefine(const vector& args, ostringstream* ostr result_t MainLoop::executeDecode(const vector& args, ostringstream* ostream) { size_t argPos = 1; - bool numeric = false, valueName = false; OutputFormat verbosity = 0; while (args.size() > argPos && args[argPos][0] == '-') { if (args[argPos] == "-v") { @@ -1593,10 +1624,9 @@ result_t MainLoop::executeDecode(const vector& args, ostringstream* ostr } else if (args[argPos] == "-vvv" || args[argPos] == "-V") { verbosity |= OF_NAMES|OF_UNITS|OF_COMMENTS; } else if (args[argPos] == "-n") { - numeric = true; + verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; } else if (args[argPos] == "-N") { - numeric = true; - valueName = true; + verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME; } else { argPos = 0; // print usage break; @@ -1622,7 +1652,6 @@ result_t MainLoop::executeDecode(const vector& args, ostringstream* ostr time_t now; time(&now); - verbosity |= valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0; istringstream defstr("#\n" + args[argPos]); // ensure first line is not used for determining col names string errorDescription; DataFieldTemplates* templates = getTemplates("*"); @@ -1865,7 +1894,7 @@ result_t MainLoop::executeHelp(ostringstream* ostream) { " hex Send hex data: hex [-s QQ] ZZPBSBNN[DD]* (if enabled)\n" " find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-a] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e]" " [-c CIRCUIT] [-l LEVEL] [NAME]\n" - " listen|l Listen for updates: listen [stop]\n" + " listen|l Listen for updates: listen [-v|-V] [-n|-N] [stop]\n" " direct Enter direct mode\n" " state|s Report bus state\n" " info|i Report information about the daemon, the configuration, and seen devices.\n" @@ -1895,7 +1924,7 @@ bool parseBoolQuery(const string& value) { } result_t MainLoop::executeGet(const vector& args, bool* connected, ostringstream* ostream) { - bool numeric = false, valueName = false, required = false, full = false, withWrite = false, raw = false; + bool required = false, full = false, withWrite = false, raw = false; bool withDefinition = false; OutputFormat verbosity = OF_NAMES; time_t maxAge = -1; @@ -1945,9 +1974,13 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri verbosity &= ~OF_NAMES; } } else if (qname == "numeric") { - numeric = parseBoolQuery(value); + if (parseBoolQuery(value)) { + verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; + } } else if (qname == "valuename") { - valueName = parseBoolQuery(value); + if (parseBoolQuery(value)) { + verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME; + } } else if (qname == "full") { full = parseBoolQuery(value); } else if (qname == "required") { @@ -1982,8 +2015,7 @@ result_t MainLoop::executeGet(const vector& args, bool* connected, ostri time_t maxLastUp = 0; if (ret == RESULT_OK) { bool first = true; - verbosity |= (valueName ? OF_VALUENAME : numeric ? OF_NUMERIC : 0) | OF_JSON | (full ? OF_ALL_ATTRS : 0) - | (withDefinition ? OF_DEFINTION : 0); + verbosity |= OF_JSON | (full ? OF_ALL_ATTRS : 0) | (withDefinition ? OF_DEFINTION : 0); deque messages; m_messages->findAll(circuit, name, getUserLevels(user), exact, true, withWrite, true, true, true, 0, 0, false, &messages); diff --git a/src/ebusd/mainloop.h b/src/ebusd/mainloop.h old mode 100755 new mode 100644 index f07f9866..742ce866 --- a/src/ebusd/mainloop.h +++ b/src/ebusd/mainloop.h @@ -144,13 +144,13 @@ class MainLoop : public Thread, DeviceListener { * @param data the data string to decode (may be empty). * @param connected set to false when the client connection shall be closed. * @param isHttp true for HTTP message. - * @param mode set to the new client mode. + * @param settings set to the new client settings. * @param user set to the new user name when changed by authentication. * @param reload set to true when the configuration files were reloaded. * @param ostream the @a ostringstream to format the result string to. * @return the result code. */ - result_t decodeMessage(const string& data, bool isHttp, bool* connected, ClientMode* mode, + result_t decodeMessage(const string& data, bool isHttp, bool* connected, ClientSettings* settings, string* user, bool* reload, ostringstream* ostream); /** @@ -238,11 +238,11 @@ class MainLoop : public Thread, DeviceListener { /** * Execute the listen command. * @param args the arguments passed to the command (starting with the command itself), or empty for help. - * @param mode set to the new client mode. + * @param settings set to the new client settings. * @param ostream the @a ostringstream to format the result string to. * @return the result code. */ - result_t executeListen(const vector& args, ClientMode* mode, ostringstream* ostream); + result_t executeListen(const vector& args, ClientSettings* settings, ostringstream* ostream); /** * Execute the state command. diff --git a/src/ebusd/network.cpp b/src/ebusd/network.cpp old mode 100755 new mode 100644 index b53831d5..dd6d0e30 --- a/src/ebusd/network.cpp +++ b/src/ebusd/network.cpp @@ -208,7 +208,7 @@ Network::~Network() { stop(); NetMessage* netMsg; while ((netMsg = m_netQueue->pop()) != nullptr) { - netMsg->setResult("ERR: shutdown", "", cm_normal, 0, true); + netMsg->setResult("ERR: shutdown", "", nullptr, 0, true); } while (!m_connections.empty()) { Connection* connection = m_connections.back(); diff --git a/src/ebusd/network.h b/src/ebusd/network.h old mode 100755 new mode 100644 index fdcabc05..cf3e8406 --- a/src/ebusd/network.h +++ b/src/ebusd/network.h @@ -23,6 +23,7 @@ #include #include #include +#include "lib/ebus/datatype.h" #include "lib/utils/tcpsocket.h" #include "lib/utils/queue.h" #include "lib/utils/notify.h" @@ -44,6 +45,14 @@ enum ClientMode { cm_direct, //!< direct mode }; +/** + * Combination of client settings. + */ +struct ClientSettings { + ClientMode mode; //!< the current client mode + OutputFormat format; //!< the output format settings for listen mode +}; + /** * Class for data/message transfer between @a Connection and @a MainLoop. */ @@ -54,7 +63,9 @@ class NetMessage { * @param isHttp whether this is a HTTP message. */ explicit NetMessage(bool isHttp) - : m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_mode(cm_normal), m_listenSince(0) { + : m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listenSince(0) { + m_settings.mode = cm_normal; + m_settings.format = 0; pthread_mutex_init(&m_mutex, nullptr); pthread_cond_init(&m_cond, nullptr); } @@ -124,16 +135,19 @@ class NetMessage { * Set the result string and notify the waiting thread. * @param result the result string. * @param user the new user name. - * @param mode the new client mode. + * @param settings the new client settings. * @param listenUntil the end time to which to updates were added (exclusive). * @param disconnect true when the client shall be disconnected. */ - void setResult(const string& result, const string& user, ClientMode mode, time_t listenUntil, bool disconnect) { + void setResult(const string& result, const string& user, ClientSettings* settings, time_t listenUntil, + bool disconnect) { pthread_mutex_lock(&m_mutex); m_result = result; m_user = user; m_disconnect = disconnect; - m_mode = mode; + if (settings) { + m_settings = *settings; + } m_listenSince = listenUntil; m_resultSet = true; pthread_cond_signal(&m_cond); @@ -141,22 +155,22 @@ class NetMessage { } /** - * Return the client mode. + * Return the client settings. * @param listenSince set listening to the specified start time from which to add updates (inclusive). - * @return the client mode. + * @return the client settings. */ - ClientMode getMode(time_t* listenSince = nullptr) { + ClientSettings getSettings(time_t* listenSince = nullptr) { if (listenSince) { *listenSince = m_listenSince; } - return m_mode; + return m_settings; } /** * Return whether this instance is in one of the listening modes. * @return whether this instance is in one of the listening modes. */ - bool isListeningMode() { return m_mode == cm_listen || m_mode == cm_direct; } + bool isListeningMode() { return m_settings.mode == cm_listen || m_settings.mode == cm_direct; } /** * Return whether the client shall be disconnected. @@ -190,8 +204,8 @@ class NetMessage { /** condition variable for exclusive lock. */ pthread_cond_t m_cond; - /** the client mode. */ - ClientMode m_mode; + /** the client settings. */ + ClientSettings m_settings; /** start timestamp of listening update. */ time_t m_listenSince; From bbfe10b9b9aea3623a38118f8b734e06ae6a1fdd Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 09:59:37 +0100 Subject: [PATCH 07/17] add option to listen to unknown messages (fixes #80) --- src/ebusd/mainloop.cpp | 43 ++++++++++++++++++++++++++++++++---------- src/ebusd/network.h | 8 ++++++-- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/ebusd/mainloop.cpp b/src/ebusd/mainloop.cpp index f39729a5..6d41e67e 100644 --- a/src/ebusd/mainloop.cpp +++ b/src/ebusd/mainloop.cpp @@ -403,13 +403,22 @@ void MainLoop::run() { } } if (settings.mode == cm_listen) { - string levels = getUserLevels(user); - messages.clear(); - m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now, true, &messages); - for (const auto message : messages) { - ostream << message->getCircuit() << " " << message->getName() << " = " << dec; - message->decodeLastData(false, nullptr, -1, settings.format, &ostream); - ostream << endl; + if (!settings.listenOnlyUnknown) { + string levels = getUserLevels(user); + messages.clear(); + m_messages->findAll("", "", levels, false, true, true, true, true, true, since, now, true, &messages); + for (const auto message : messages) { + ostream << message->getCircuit() << " " << message->getName() << " = " << dec; + message->decodeLastData(false, nullptr, -1, settings.format, &ostream); + ostream << endl; + } + } + if (settings.listenWithUnknown || settings.listenOnlyUnknown) { + if (m_busHandler->isGrabEnabled()) { + m_busHandler->formatGrabResult(true, false, &ostream, true, since, now); + } else { + m_busHandler->enableGrab(true); // needed for listening to all messages + } } } else if (settings.mode == cm_direct) { if (m_busHandler->isGrabEnabled()) { @@ -1480,6 +1489,8 @@ result_t MainLoop::executeFind(const vector& args, const string& levels, result_t MainLoop::executeListen(const vector& args, ClientSettings* settings, ostringstream* ostream) { size_t argPos = 1; OutputFormat verbosity = 0; + bool listenWithUnknown = false; + bool listenOnlyUnknown = false; while (args.size() > argPos && args[argPos][0] == '-') { if (args[argPos] == "-v") { switch (verbosity) { @@ -1501,6 +1512,11 @@ result_t MainLoop::executeListen(const vector& args, ClientSettings* set verbosity = (verbosity & ~OF_VALUENAME) | OF_NUMERIC; } else if (args[argPos] == "-N") { verbosity = (verbosity & ~OF_NUMERIC) | OF_VALUENAME; + } else if (args[argPos] == "-u") { + listenWithUnknown = true; + listenOnlyUnknown = false; + } else if (args[argPos] == "-U") { + listenOnlyUnknown = true; } else { argPos = 0; // print usage break; @@ -1509,6 +1525,11 @@ result_t MainLoop::executeListen(const vector& args, ClientSettings* set } if (argPos > 0 && args.size() == argPos) { settings->format = verbosity; + settings->listenWithUnknown = listenWithUnknown; + settings->listenOnlyUnknown = listenOnlyUnknown; + if (listenWithUnknown || listenOnlyUnknown) { + m_busHandler->enableGrab(true); // needed for listening to all messages + } if (settings->mode == cm_listen) { *ostream << "listen continued"; return RESULT_OK; @@ -1519,12 +1540,14 @@ result_t MainLoop::executeListen(const vector& args, ClientSettings* set } if (argPos == 0 || args.size() != argPos + 1 || args[argPos] != "stop") { - *ostream << "usage: listen [-v|-V] [-n|-N] [stop]\n" + *ostream << "usage: listen [-v|-V] [-n|-N] [-u|-U] [stop]\n" " Listen for updates or stop it.\n" " -v increase verbosity (include names/units/comments)\n" " -V be very verbose (include names, units, and comments)\n" " -n use numeric value of value=name pairs\n" - " -N use numeric and named value of value=name pairs"; + " -N use numeric and named value of value=name pairs\n" + " -u include unknown messages\n" + " -U only show unknown messages"; return RESULT_OK; } settings->mode = cm_normal; @@ -1894,7 +1917,7 @@ result_t MainLoop::executeHelp(ostringstream* ostream) { " hex Send hex data: hex [-s QQ] ZZPBSBNN[DD]* (if enabled)\n" " find|f Find message(s): find [-v|-V] [-r] [-w] [-p] [-a] [-d] [-h] [-i ID] [-f] [-F COL[,COL]*] [-e]" " [-c CIRCUIT] [-l LEVEL] [NAME]\n" - " listen|l Listen for updates: listen [-v|-V] [-n|-N] [stop]\n" + " listen|l Listen for updates: listen [-v|-V] [-n|-N] [-u|-U] [stop]\n" " direct Enter direct mode\n" " state|s Report bus state\n" " info|i Report information about the daemon, the configuration, and seen devices.\n" diff --git a/src/ebusd/network.h b/src/ebusd/network.h index cf3e8406..dd921e16 100644 --- a/src/ebusd/network.h +++ b/src/ebusd/network.h @@ -49,8 +49,10 @@ enum ClientMode { * Combination of client settings. */ struct ClientSettings { - ClientMode mode; //!< the current client mode - OutputFormat format; //!< the output format settings for listen mode + ClientMode mode; //!< the current client mode + OutputFormat format; //!< the output format settings for listen mode + bool listenWithUnknown; //!< include unknown messages in listen mode + bool listenOnlyUnknown; //!< only print unknown messages in listen mode }; /** @@ -66,6 +68,8 @@ class NetMessage { : m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listenSince(0) { m_settings.mode = cm_normal; m_settings.format = 0; + m_settings.listenWithUnknown = false; + m_settings.listenOnlyUnknown = false; pthread_mutex_init(&m_mutex, nullptr); pthread_cond_init(&m_cond, nullptr); } From 3a4bd476e6aee8a13cc72d4a1e02639ad2b19975 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 10:00:22 +0100 Subject: [PATCH 08/17] updated --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 9d314716..85acd03b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,7 @@ * fix for compilation and running on FreeBSD and MacOS with low latency setting for FTDI device (thanks to samm-git) * fix for switching to daemon mode when log file was not opened * fix for checking required arguments of "write" command with "-h" +* fix for potential MQTT reconnect issue after lost connection ## Features * added option to set poll priority with MQTT get topic @@ -17,6 +18,7 @@ * added MQTT /list topic for retrieval of all known messages * added support for init scripts on non-LSB distributions (thanks to andr2000) * added support for logging to syslog instead of file (thanks to samm-git) +* added adjustable verbosity and option to include unknown messages to "listen" command # 3.3 (2018-12-26) From d6e59c8422da01e394440ee0fb5e657c187671fe Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 10:15:27 +0100 Subject: [PATCH 09/17] set exit code in checkconfig (fixes #297) --- src/ebusd/main.cpp | 27 ++++++++++++++++++++------- src/ebusd/main.h | 3 ++- 2 files changed, 22 insertions(+), 8 deletions(-) mode change 100755 => 100644 src/ebusd/main.h diff --git a/src/ebusd/main.cpp b/src/ebusd/main.cpp index d9bb90dc..54803402 100644 --- a/src/ebusd/main.cpp +++ b/src/ebusd/main.cpp @@ -662,7 +662,7 @@ void closePidFile() { /** * Helper method performing shutdown. */ -void shutdown() { +void shutdown(bool error = false) { // stop main loop and all dependent components if (s_mainLoop) { delete s_mainLoop; @@ -691,7 +691,7 @@ void shutdown() { logNotice(lf_main, "ebusd stopped"); closeLogFile(); - exit(EXIT_SUCCESS); + exit(error ? EXIT_FAILURE : EXIT_SUCCESS); } /** @@ -929,7 +929,7 @@ void readMessage(Message* message) { } } -void executeInstructions(MessageMap* messages, bool verbose) { +result_t executeInstructions(MessageMap* messages, bool verbose) { string errorDescription; result_t result = messages->resolveConditions(verbose, &errorDescription); if (result != RESULT_OK) { @@ -946,6 +946,7 @@ void executeInstructions(MessageMap* messages, bool verbose) { } logNotice(lf_main, "found messages: %d (%d conditional on %d conditions, %d poll, %d update)", messages->size(), messages->sizeConditional(), messages->sizeConditions(), messages->sizePoll(), messages->sizePassive()); + return result; } result_t loadDefinitionsFromConfigPath(FileReader* reader, const string& filename, bool verbose, @@ -993,7 +994,7 @@ result_t loadConfigFiles(MessageMap* messages, bool verbose, bool denyRecursive) getResultCode(result), errorDescription.c_str()); } messages->unlock(); - return RESULT_OK; + return opt.checkConfig ? result : RESULT_OK; } result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose, string* relativeFile) { @@ -1256,7 +1257,7 @@ int main(int argc, char* argv[]) { logNotice(lf_main, PACKAGE_STRING "." REVISION " performing configuration check..."); result_t result = loadConfigFiles(s_messageMap, true, opt.scanConfig && arg_index < argc); - executeInstructions(s_messageMap, true); + result_t overallResult = executeInstructions(s_messageMap, true); MasterSymbolString master; SlaveSymbolString slave; while (result == RESULT_OK && opt.scanConfig && arg_index < argc) { @@ -1268,21 +1269,33 @@ int main(int argc, char* argv[]) { Message* message = s_messageMap->getScanMessage(address); if (!message) { logError(lf_main, "invalid scan address %2.2x", address); + if (overallResult == RESULT_OK) { + overallResult = RESULT_ERR_INVALID_ADDR; + } } else { message->storeLastData(master, slave); string file; result_t res = loadScanConfigFile(s_messageMap, address, true, &file); - executeInstructions(s_messageMap, true); + result_t instrRes = executeInstructions(s_messageMap, true); if (res == RESULT_OK) { logInfo(lf_main, "scan config %2.2x: file %s loaded", address, file.c_str()); + } else if (overallResult == RESULT_OK) { + overallResult = res; + } + if (overallResult == RESULT_OK && instrRes != RESULT_OK) { + overallResult = instrRes; } } } + if (result != RESULT_OK) { + overallResult = result; + } if (result == RESULT_OK && opt.dumpConfig) { logNotice(lf_main, "configuration dump:"); s_messageMap->dump(true, &cout); } - shutdown(); + + shutdown(overallResult != RESULT_OK); return 0; } diff --git a/src/ebusd/main.h b/src/ebusd/main.h old mode 100755 new mode 100644 index f662879d..97717af0 --- a/src/ebusd/main.h +++ b/src/ebusd/main.h @@ -120,8 +120,9 @@ result_t loadScanConfigFile(MessageMap* messages, symbol_t address, bool verbose * Helper method for executing all loaded and resolvable instructions. * @param messages the @a MessageMap instance. * @param verbose whether to verbosely log all problems. + * @return the result code. */ -void executeInstructions(MessageMap* messages, bool verbose = false); +result_t executeInstructions(MessageMap* messages, bool verbose = false); /** * Helper method for loading definitions from a relative file from the config path/URL. From 0038c3a2d20b07eb173defa112e3e1207bfe2099 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 10:27:19 +0100 Subject: [PATCH 10/17] removed outdated ref --- contrib/docker/update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 contrib/docker/update.sh diff --git a/contrib/docker/update.sh b/contrib/docker/update.sh old mode 100755 new mode 100644 index 9112abaf..a9b8f176 --- a/contrib/docker/update.sh +++ b/contrib/docker/update.sh @@ -2,5 +2,5 @@ set -e export EBUSD_VERSION=`cat ../../VERSION` export EBUSD_ARCH=`docker version|grep -i "Arch[^:]*:"|tail -n 1|sed -e 's#^.*/##'` -sed -i -e "s#^ENV EBUSD_VERSION .*\$#ENV EBUSD_VERSION ${EBUSD_VERSION}#" -e "s#^ENV EBUSD_ARCH .*\$#ENV EBUSD_ARCH ${EBUSD_ARCH}#" Dockerfile release/Dockerfile runtime/Dockerfile +sed -i -e "s#^ENV EBUSD_VERSION .*\$#ENV EBUSD_VERSION ${EBUSD_VERSION}#" -e "s#^ENV EBUSD_ARCH .*\$#ENV EBUSD_ARCH ${EBUSD_ARCH}#" Dockerfile release/Dockerfile From 57eae053c7b26301ee7a0d79b975aacc66058b46 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 10:27:58 +0100 Subject: [PATCH 11/17] updated version to 3.4 --- ChangeLog.md | 2 +- VERSION | 2 +- contrib/archlinux/PKGBUILD | 2 +- contrib/archlinux/PKGBUILD.git | 2 +- contrib/docker/Dockerfile | 2 +- contrib/docker/release/Dockerfile | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 85acd03b..69f0b7d6 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,4 @@ -# 3.4 (2019-10-?) +# 3.4 (2019-10-27) ## Bug Fixes * fix for always enabled "--mqttchanges" option diff --git a/VERSION b/VERSION index f30101c0..af1817b0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.3 \ No newline at end of file +3.4 \ No newline at end of file diff --git a/contrib/archlinux/PKGBUILD b/contrib/archlinux/PKGBUILD index 867baf3f..445f7c23 100644 --- a/contrib/archlinux/PKGBUILD +++ b/contrib/archlinux/PKGBUILD @@ -2,7 +2,7 @@ # Contributor: Milan Knizek # Usage: makepkg pkgname=ebusd -pkgver=3.3 +pkgver=3.4 pkgrel=1 pkgdesc="ebusd, the daemon for communication with eBUS heating systems." arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') diff --git a/contrib/archlinux/PKGBUILD.git b/contrib/archlinux/PKGBUILD.git index cba8bebb..afa50faf 100644 --- a/contrib/archlinux/PKGBUILD.git +++ b/contrib/archlinux/PKGBUILD.git @@ -3,7 +3,7 @@ # Usage: makepkg -p PKGBUILD.git pkgname=ebusd-git _gitname=ebusd -pkgver=3.3 +pkgver=3.4 pkgrel=1 pkgdesc="ebusd, the daemon for communication with eBUS heating systems." arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') diff --git a/contrib/docker/Dockerfile b/contrib/docker/Dockerfile index ad939472..4e0ccc5e 100755 --- a/contrib/docker/Dockerfile +++ b/contrib/docker/Dockerfile @@ -12,7 +12,7 @@ RUN apt-get update && apt-get install -y \ LABEL maintainer "ebusd@ebusd.eu" -ENV EBUSD_VERSION 3.3 +ENV EBUSD_VERSION 3.4 ENV EBUSD_ARCH amd64 LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}-devel" diff --git a/contrib/docker/release/Dockerfile b/contrib/docker/release/Dockerfile index fe10ab69..b85cdecb 100755 --- a/contrib/docker/release/Dockerfile +++ b/contrib/docker/release/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get update && apt-get install -y \ LABEL maintainer "ebusd@ebusd.eu" -ENV EBUSD_VERSION 3.3 +ENV EBUSD_VERSION 3.4 ENV EBUSD_ARCH amd64 LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" From 43f7660d6602bfc0c6ac9af01e35464dd26c8238 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 11:20:08 +0000 Subject: [PATCH 12/17] updated to 3.4 md5sum --- contrib/archlinux/PKGBUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/archlinux/PKGBUILD b/contrib/archlinux/PKGBUILD index 445f7c23..73b7781f 100644 --- a/contrib/archlinux/PKGBUILD +++ b/contrib/archlinux/PKGBUILD @@ -37,4 +37,4 @@ package() { install -m 0644 contrib/archlinux/conf.d/ebusd "${pkgdir}/etc/conf.d/ebusd" } # update md5sums: updpkgsums -md5sums=('f65252d59ccce4c244d3c4c5597a6b8e') +md5sums=('0ce4e4646445612373d5114bb2f99fa8') From 819463fc270123b08ee11d94c49b1d3b1a874425 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 27 Oct 2019 14:31:18 +0100 Subject: [PATCH 13/17] add info for browsers --- contrib/updatecheck/index.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/contrib/updatecheck/index.php b/contrib/updatecheck/index.php index 6a4f092e..7fa4dc7a 100644 --- a/contrib/updatecheck/index.php +++ b/contrib/updatecheck/index.php @@ -1,12 +1,20 @@ + + + ebusd update check service + + +

latest ebusd version:

+

last update:

+ From 3e7e4c7a3cffe8bd4b1f29df8f8aa8607b895546 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 10 Nov 2019 19:04:05 +0100 Subject: [PATCH 14/17] add RPi version (fix #267) --- contrib/docker/rpirelease/Dockerfile | 25 +++++++++++++++++++ .../docker/rpirelease/docker-entrypoint.sh | 8 ++++++ 2 files changed, 33 insertions(+) create mode 100755 contrib/docker/rpirelease/Dockerfile create mode 100755 contrib/docker/rpirelease/docker-entrypoint.sh diff --git a/contrib/docker/rpirelease/Dockerfile b/contrib/docker/rpirelease/Dockerfile new file mode 100755 index 00000000..49e8c12a --- /dev/null +++ b/contrib/docker/rpirelease/Dockerfile @@ -0,0 +1,25 @@ +FROM balenalib/raspberrypi3 + +RUN apt-get update && apt-get install -y \ + logrotate libmosquitto1 libstdc++6 libc6 libgcc1 \ + curl \ + && rm -rf /var/lib/apt/lists/* + +LABEL maintainer "ebusd@ebusd.eu" + +ENV EBUSD_VERSION 3.4 +ENV EBUSD_ARCH armhf + +LABEL version "${EBUSD_VERSION}-${EBUSD_ARCH}" + +RUN curl -SL https://github.com/john30/ebusd/releases/download/v${EBUSD_VERSION}/ebusd-${EBUSD_VERSION}_${EBUSD_ARCH}-stretch_mqtt1.deb > ebusd.deb + +RUN dpkg -i ebusd.deb + +RUN rm ebusd.deb + +EXPOSE 8888 + +COPY docker-entrypoint.sh / +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["-f", "--scanconfig"] diff --git a/contrib/docker/rpirelease/docker-entrypoint.sh b/contrib/docker/rpirelease/docker-entrypoint.sh new file mode 100755 index 00000000..142a9a26 --- /dev/null +++ b/contrib/docker/rpirelease/docker-entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +if [ "${1#-}" != "$1" ]; then + set -- ebusd "$@" +fi + +exec "$@" \ No newline at end of file From f55101d9a681a84112e3020a5bb77158013b2c1f Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 10 Nov 2019 19:30:35 +0100 Subject: [PATCH 15/17] update rpi as well --- contrib/docker/update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/docker/update.sh b/contrib/docker/update.sh index a9b8f176..495b7b32 100644 --- a/contrib/docker/update.sh +++ b/contrib/docker/update.sh @@ -2,5 +2,5 @@ set -e export EBUSD_VERSION=`cat ../../VERSION` export EBUSD_ARCH=`docker version|grep -i "Arch[^:]*:"|tail -n 1|sed -e 's#^.*/##'` -sed -i -e "s#^ENV EBUSD_VERSION .*\$#ENV EBUSD_VERSION ${EBUSD_VERSION}#" -e "s#^ENV EBUSD_ARCH .*\$#ENV EBUSD_ARCH ${EBUSD_ARCH}#" Dockerfile release/Dockerfile +sed -i -e "s#^ENV EBUSD_VERSION .*\$#ENV EBUSD_VERSION ${EBUSD_VERSION}#" -e "s#^ENV EBUSD_ARCH .*\$#ENV EBUSD_ARCH ${EBUSD_ARCH}#" Dockerfile release/Dockerfile rpirelease/Dockerfile From 87b3705e3a144e5c9c258429a780c871c9ce05e5 Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 17 Nov 2019 10:22:20 +0100 Subject: [PATCH 16/17] fix for concatenation of several update messages (fixes #309 and fixes #312) --- src/ebusd/mqtthandler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ebusd/mqtthandler.cpp b/src/ebusd/mqtthandler.cpp index 7460acc7..1ded7a24 100644 --- a/src/ebusd/mqtthandler.cpp +++ b/src/ebusd/mqtthandler.cpp @@ -752,12 +752,12 @@ void MqttHandler::run() { for (auto it = m_updatedMessages.begin(); it != m_updatedMessages.end(); ) { const vector* messages = m_messages->getByKey(it->first); if (messages) { - updates.str(""); - updates.clear(); - updates << dec; for (auto message : *messages) { if (message->getLastChangeTime() > 0 && message->isAvailable() && (!g_onlyChanges || message->getLastChangeTime() > lastUpdates)) { + updates.str(""); + updates.clear(); + updates << dec; publishMessage(message, &updates); } } From f15279815e55aef00a637b1ea6ec51053760e6cd Mon Sep 17 00:00:00 2001 From: john30 Date: Sun, 24 Nov 2019 12:15:00 +0100 Subject: [PATCH 17/17] fix for use with xargs --- src/tools/ebusctl.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/ebusctl.cpp b/src/tools/ebusctl.cpp index 518a52d3..71d2d9e4 100755 --- a/src/tools/ebusctl.cpp +++ b/src/tools/ebusctl.cpp @@ -227,6 +227,9 @@ string fetchData(ebusd::TCPSocket* socket, bool listening) { } } else if (newInput) { getline(cin, message); + if (message.length()==0) { + continue; + } sendmessage = message+'\n'; socket->send(sendmessage.c_str(), sendmessage.size());