extract request related parts
This commit is contained in:
@@ -3,6 +3,7 @@ add_definitions(-Wconversion -Wno-unused-parameter)
|
||||
set(ebusd_SOURCES
|
||||
bushandler.h bushandler.cpp
|
||||
datahandler.h datahandler.cpp
|
||||
request.h request.cpp
|
||||
network.h network.cpp
|
||||
mainloop.h mainloop.cpp
|
||||
scan.h scan.cpp
|
||||
|
||||
+28
-4
@@ -31,6 +31,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "ebusd/mainloop.h"
|
||||
#include "ebusd/network.h"
|
||||
#include "lib/utils/log.h"
|
||||
#include "lib/utils/httpclient.h"
|
||||
#include "ebusd/scan.h"
|
||||
@@ -143,9 +144,15 @@ static MessageMap* s_messageMap = nullptr;
|
||||
/** the @a ScanHelper instance, or nullptr. */
|
||||
static ScanHelper* s_scanHelper = nullptr;
|
||||
|
||||
/** the @a Request @a Queue instance, or nullptr. */
|
||||
static Queue<Request*>* s_requestQueue = nullptr;
|
||||
|
||||
/** the @a MainLoop instance, or nullptr. */
|
||||
static MainLoop* s_mainLoop = nullptr;
|
||||
|
||||
/** the @a Network instance, or nullptr. */
|
||||
static Network* s_network = nullptr;
|
||||
|
||||
/** the (optionally corrected) config path for retrieving configuration files from. */
|
||||
static string s_configPath = CONFIG_PATH;
|
||||
|
||||
@@ -735,15 +742,27 @@ void daemonize() {
|
||||
* Clean up all dynamically allocated and stop main loop and all dependent components.
|
||||
*/
|
||||
void cleanup() {
|
||||
if (s_mainLoop) {
|
||||
if (s_network != nullptr) {
|
||||
delete s_network;
|
||||
s_network = nullptr;
|
||||
}
|
||||
if (s_mainLoop != nullptr) {
|
||||
delete s_mainLoop;
|
||||
s_mainLoop = nullptr;
|
||||
}
|
||||
if (s_messageMap) {
|
||||
if (s_requestQueue != nullptr) {
|
||||
Request* msg;
|
||||
while ((msg = s_requestQueue->pop()) != nullptr) {
|
||||
delete msg;
|
||||
}
|
||||
delete s_requestQueue;
|
||||
s_requestQueue = nullptr;
|
||||
}
|
||||
if (s_messageMap != nullptr) {
|
||||
delete s_messageMap;
|
||||
s_messageMap = nullptr;
|
||||
}
|
||||
if (s_scanHelper) {
|
||||
if (s_scanHelper != nullptr) {
|
||||
delete s_scanHelper;
|
||||
s_scanHelper = nullptr;
|
||||
}
|
||||
@@ -1030,8 +1049,10 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
// load configuration files
|
||||
s_scanHelper->loadConfigFiles(!s_opt.scanConfig);
|
||||
|
||||
s_requestQueue = new Queue<Request*>();
|
||||
|
||||
// create the MainLoop and start it
|
||||
s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper);
|
||||
s_mainLoop = new MainLoop(s_opt, device, s_messageMap, s_scanHelper, s_requestQueue);
|
||||
if (s_opt.injectMessages) {
|
||||
BusHandler* busHandler = s_mainLoop->getBusHandler();
|
||||
int scanAdrCount = 0;
|
||||
@@ -1064,6 +1085,9 @@ int main(int argc, char* argv[], char* envp[]) {
|
||||
}
|
||||
s_mainLoop->start("mainloop");
|
||||
|
||||
s_network = new Network(s_opt.localOnly, s_opt.port, s_opt.httpPort, s_requestQueue);
|
||||
s_network->start("network");
|
||||
|
||||
// wait for end of MainLoop
|
||||
s_mainLoop->join();
|
||||
|
||||
|
||||
+46
-91
@@ -105,12 +105,13 @@ result_t UserList::addFromFile(const string& filename, unsigned int lineNo, map<
|
||||
#define VERBOSITY_4 (VERBOSITY_3 | OF_ALL_ATTRS)
|
||||
|
||||
|
||||
MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messages, ScanHelper* scanHelper)
|
||||
MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messages, ScanHelper* scanHelper,
|
||||
Queue<Request*>* requestQueue)
|
||||
: Thread(), m_device(device), m_reconnectCount(0), m_userList(opt.accessLevel), m_messages(messages),
|
||||
m_scanHelper(scanHelper), m_address(opt.address), m_scanConfig(opt.scanConfig),
|
||||
m_initialScan(opt.readOnly ? ESC : opt.initialScan), m_scanStatus(SCAN_STATUS_NONE),
|
||||
m_polling(opt.pollInterval > 0), m_enableHex(opt.enableHex),
|
||||
m_shutdown(false), m_runUpdateCheck(opt.updateCheck), m_httpClient() {
|
||||
m_shutdown(false), m_runUpdateCheck(opt.updateCheck), m_httpClient(), m_requestQueue(requestQueue) {
|
||||
m_device->setListener(this);
|
||||
// open Device
|
||||
result_t result = m_device->open();
|
||||
@@ -160,8 +161,6 @@ MainLoop::MainLoop(const struct options& opt, Device *device, MessageMap* messag
|
||||
|
||||
// create network
|
||||
m_htmlPath = opt.htmlPath;
|
||||
m_network = new Network(opt.localOnly, opt.port, opt.httpPort, &m_netQueue);
|
||||
m_network->start("network");
|
||||
logInfo(lf_main, "registering data handlers");
|
||||
if (datahandler_register(&m_userList, m_busHandler, messages, &m_dataHandlers)) {
|
||||
logInfo(lf_main, "registered data handlers");
|
||||
@@ -192,10 +191,6 @@ MainLoop::~MainLoop() {
|
||||
delete m_logRawFile;
|
||||
m_logRawFile = nullptr;
|
||||
}
|
||||
if (m_network != nullptr) {
|
||||
delete m_network;
|
||||
m_network = nullptr;
|
||||
}
|
||||
if (m_busHandler != nullptr) {
|
||||
delete m_busHandler;
|
||||
m_busHandler = nullptr;
|
||||
@@ -204,10 +199,6 @@ MainLoop::~MainLoop() {
|
||||
delete m_device;
|
||||
m_device = nullptr;
|
||||
}
|
||||
NetMessage* msg;
|
||||
while ((msg = m_netQueue.pop()) != nullptr) {
|
||||
delete msg;
|
||||
}
|
||||
if (m_newlyDefinedMessages) {
|
||||
delete m_newlyDefinedMessages;
|
||||
m_newlyDefinedMessages = nullptr;
|
||||
@@ -245,8 +236,8 @@ void MainLoop::run() {
|
||||
dataHandler->startHandler();
|
||||
}
|
||||
while (!m_shutdown) {
|
||||
// pick the next message to handle
|
||||
NetMessage* netMessage = m_netQueue.pop(taskDelay);
|
||||
// pick the next request to handle
|
||||
Request* req = m_requestQueue->pop(taskDelay);
|
||||
time(&now);
|
||||
if (now < lastTaskRun) {
|
||||
// clock skew
|
||||
@@ -410,66 +401,62 @@ void MainLoop::run() {
|
||||
m_messages->unlock();
|
||||
sinkSince = now;
|
||||
}
|
||||
if (netMessage == nullptr) {
|
||||
if (req == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (m_shutdown) {
|
||||
netMessage->setResult("ERR: shutdown", "", nullptr, now, true);
|
||||
req->setResult("ERR: shutdown", "", nullptr, now, true);
|
||||
break;
|
||||
}
|
||||
string request = netMessage->getRequest();
|
||||
string user = netMessage->getUser();
|
||||
ClientSettings settings = netMessage->getSettings(&since);
|
||||
if (!netMessage->isListeningMode()) {
|
||||
string user = req->getUser();
|
||||
RequestMode reqMode = req->getMode(&since);
|
||||
if (reqMode.listenMode == lm_none) {
|
||||
since = now;
|
||||
}
|
||||
ostringstream ostream;
|
||||
bool connected = true;
|
||||
if (request.length() > 0) {
|
||||
logDebug(lf_main, ">>> %s", request.c_str());
|
||||
result_t result = decodeMessage(request, netMessage->isHttp(), &connected, &settings, &user, &reload, &ostream);
|
||||
if (!netMessage->isHttp() && (ostream.tellp() == 0 || result != RESULT_OK)) {
|
||||
if (settings.mode != cm_direct) {
|
||||
if (!req->empty()) {
|
||||
req->log();
|
||||
result_t result = decodeRequest(req, &connected, &reqMode, &user, &reload, &ostream);
|
||||
if (!req->isHttp() && (ostream.tellp() == 0 || result != RESULT_OK)) {
|
||||
if (reqMode.listenMode != lm_direct) {
|
||||
ostream.str("");
|
||||
}
|
||||
ostream << getResultCode(result);
|
||||
}
|
||||
if (ostream.tellp() > 100) {
|
||||
logDebug(lf_main, "<<< %s ...", ostream.str().substr(0, 100).c_str());
|
||||
} else {
|
||||
logDebug(lf_main, "<<< %s", ostream.str().c_str());
|
||||
}
|
||||
const auto resp = ostream.str();
|
||||
req->log(&resp);
|
||||
if (ostream.tellp() == 0) {
|
||||
ostream << "\n"; // only for HTTP
|
||||
} else if (!netMessage->isHttp()) {
|
||||
ostream << (settings.mode == cm_direct ? "\n" : "\n\n");
|
||||
} else if (!req->isHttp()) {
|
||||
ostream << (reqMode.listenMode == lm_direct ? "\n" : "\n\n");
|
||||
}
|
||||
}
|
||||
if (settings.mode == cm_listen) {
|
||||
if (!settings.listenOnlyUnknown) {
|
||||
if (reqMode.listenMode == lm_listen) {
|
||||
if (!reqMode.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);
|
||||
message->decodeLastData(false, nullptr, -1, reqMode.format, &ostream);
|
||||
ostream << endl;
|
||||
}
|
||||
}
|
||||
if (settings.listenWithUnknown || settings.listenOnlyUnknown) {
|
||||
if (reqMode.listenWithUnknown || reqMode.listenOnlyUnknown) {
|
||||
if (m_busHandler->isGrabEnabled()) {
|
||||
m_busHandler->formatGrabResult(true, OF_NONE, &ostream, true, since, now);
|
||||
} else {
|
||||
m_busHandler->enableGrab(true); // needed for listening to all messages
|
||||
}
|
||||
}
|
||||
} else if (settings.mode == cm_direct) {
|
||||
} else if (reqMode.listenMode == lm_direct) {
|
||||
if (m_busHandler->isGrabEnabled()) {
|
||||
m_busHandler->formatGrabResult(false, OF_NONE, &ostream, true, since, now);
|
||||
}
|
||||
}
|
||||
// send result to client
|
||||
netMessage->setResult(ostream.str(), user, &settings, now, !connected);
|
||||
req->setResult(ostream.str(), user, &reqMode, now, !connected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,49 +516,18 @@ void MainLoop::notifyStatus(bool error, const char* message) {
|
||||
}
|
||||
}
|
||||
|
||||
result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connected, ClientSettings* settings,
|
||||
result_t MainLoop::decodeRequest(Request* req, bool* connected, RequestMode* reqMode,
|
||||
string* user, bool* reload, ostringstream* ostream) {
|
||||
string token, previous;
|
||||
istringstream stream(data);
|
||||
vector<string> args;
|
||||
char escaped = 0;
|
||||
|
||||
char delim = ' ';
|
||||
while (getline(stream, token, delim)) {
|
||||
if (!isHttp) {
|
||||
if (escaped) {
|
||||
args.pop_back();
|
||||
if (token.length() > 0 && token[token.length()-1] == escaped) {
|
||||
token.erase(token.length() - 1, 1);
|
||||
escaped = 0;
|
||||
}
|
||||
token = previous + " " + token;
|
||||
} else if (token.length() == 0) { // allow multiple space chars for a single delimiter
|
||||
continue;
|
||||
} else if (token[0] == '"' || token[0] == '\'') {
|
||||
escaped = token[0];
|
||||
token.erase(0, 1);
|
||||
if (token.length() > 0 && token[token.length()-1] == escaped) {
|
||||
token.erase(token.length() - 1, 1);
|
||||
escaped = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
args.push_back(token);
|
||||
previous = token;
|
||||
if (isHttp) {
|
||||
delim = (args.size() == 1) ? '?' : '\n';
|
||||
}
|
||||
}
|
||||
|
||||
if (isHttp) {
|
||||
req->split(&args);
|
||||
string cmd = args.size() > 0 ? args[0] : "";
|
||||
if (req->isHttp()) {
|
||||
if (args.size() < 2) {
|
||||
*connected = false;
|
||||
*ostream << "HTTP/1.0 400 Bad Request\r\n\r\n";
|
||||
return RESULT_OK;
|
||||
}
|
||||
const char* str = args.size() > 0 ? args[0].c_str() : "";
|
||||
if (strcmp(str, "GET") == 0) {
|
||||
if (cmd == "GET") {
|
||||
return executeGet(args, connected, ostream);
|
||||
}
|
||||
*connected = false;
|
||||
@@ -579,7 +535,6 @@ result_t MainLoop::decodeMessage(const string &data, bool isHttp, bool* connecte
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
string cmd = args.size() > 0 ? args[0] : "";
|
||||
transform(cmd.begin(), cmd.end(), cmd.begin(), ::toupper);
|
||||
if (cmd == "?" || cmd == "H" || cmd == "HELP") {
|
||||
// found "HELP CMD"
|
||||
@@ -587,8 +542,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 (settings->mode == cm_direct) {
|
||||
return executeDirect(args, &settings->mode, ostream);
|
||||
if (reqMode->listenMode == lm_direct) {
|
||||
return executeDirect(args, reqMode, ostream);
|
||||
}
|
||||
if (cmd.empty() && args.size() == 0) {
|
||||
return executeHelp(ostream);
|
||||
@@ -620,10 +575,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, settings, ostream);
|
||||
return executeListen(args, reqMode, ostream);
|
||||
}
|
||||
if (cmd == "DIRECT") {
|
||||
return executeDirect(args, &settings->mode, ostream);
|
||||
return executeDirect(args, reqMode, ostream);
|
||||
}
|
||||
if (cmd == "S" || cmd == "STATE") {
|
||||
return executeState(args, ostream);
|
||||
@@ -1293,10 +1248,10 @@ result_t MainLoop::executeHex(const vector<string>& args, ostringstream* ostream
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t MainLoop::executeDirect(const vector<string>& args, ClientMode* mode, ostringstream* ostream) {
|
||||
if (*mode != cm_direct) {
|
||||
result_t MainLoop::executeDirect(const vector<string>& args, RequestMode* reqMode, ostringstream* ostream) {
|
||||
if (reqMode->listenMode != lm_direct) {
|
||||
if (args.size() == 1) {
|
||||
*mode = cm_direct;
|
||||
reqMode->listenMode = lm_direct;
|
||||
m_busHandler->enableGrab(true); // needed for listening to all messages
|
||||
*ostream << "direct mode started";
|
||||
return RESULT_OK;
|
||||
@@ -1308,7 +1263,7 @@ result_t MainLoop::executeDirect(const vector<string>& args, ClientMode* mode, o
|
||||
if (args.size() > 0) {
|
||||
string firstArg = args[0];
|
||||
if (firstArg == "stop") {
|
||||
*mode = cm_normal;
|
||||
reqMode->listenMode = lm_none;
|
||||
*ostream << "direct mode stopped";
|
||||
return RESULT_OK;
|
||||
}
|
||||
@@ -1321,7 +1276,7 @@ result_t MainLoop::executeDirect(const vector<string>& args, ClientMode* mode, o
|
||||
}
|
||||
*ostream << ":";
|
||||
if (!m_enableHex) {
|
||||
*ostream << "ERR: command not enabled";
|
||||
*ostream << "ERR: hex command not enabled";
|
||||
return RESULT_OK;
|
||||
}
|
||||
size_t argPos = 0;
|
||||
@@ -1560,7 +1515,7 @@ result_t MainLoop::executeFind(const vector<string>& args, const string& levels,
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
result_t MainLoop::executeListen(const vector<string>& args, ClientSettings* settings, ostringstream* ostream) {
|
||||
result_t MainLoop::executeListen(const vector<string>& args, RequestMode* reqMode, ostringstream* ostream) {
|
||||
size_t argPos = 1;
|
||||
OutputFormat verbosity = OF_NONE;
|
||||
bool listenWithUnknown = false;
|
||||
@@ -1594,17 +1549,17 @@ result_t MainLoop::executeListen(const vector<string>& args, ClientSettings* set
|
||||
argPos++;
|
||||
}
|
||||
if (argPos > 0 && args.size() == argPos) {
|
||||
settings->format = verbosity;
|
||||
settings->listenWithUnknown = listenWithUnknown;
|
||||
settings->listenOnlyUnknown = listenOnlyUnknown;
|
||||
reqMode->format = verbosity;
|
||||
reqMode->listenWithUnknown = listenWithUnknown;
|
||||
reqMode->listenOnlyUnknown = listenOnlyUnknown;
|
||||
if (listenWithUnknown || listenOnlyUnknown) {
|
||||
m_busHandler->enableGrab(true); // needed for listening to all messages
|
||||
}
|
||||
if (settings->mode == cm_listen) {
|
||||
if (reqMode->listenMode == lm_listen) {
|
||||
*ostream << "listen continued";
|
||||
return RESULT_OK;
|
||||
}
|
||||
settings->mode = cm_listen;
|
||||
reqMode->listenMode = lm_listen;
|
||||
*ostream << "listen started";
|
||||
return RESULT_OK;
|
||||
}
|
||||
@@ -1620,7 +1575,7 @@ result_t MainLoop::executeListen(const vector<string>& args, ClientSettings* set
|
||||
" -U only show unknown messages";
|
||||
return RESULT_OK;
|
||||
}
|
||||
settings->mode = cm_normal;
|
||||
reqMode->listenMode = lm_none;
|
||||
*ostream << "listen stopped";
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
+15
-23
@@ -26,7 +26,7 @@
|
||||
#include <algorithm>
|
||||
#include "ebusd/bushandler.h"
|
||||
#include "ebusd/datahandler.h"
|
||||
#include "ebusd/network.h"
|
||||
#include "ebusd/request.h"
|
||||
#include "ebusd/scan.h"
|
||||
#include "lib/ebus/filereader.h"
|
||||
#include "lib/ebus/message.h"
|
||||
@@ -102,13 +102,15 @@ class UserList : public UserInfo, public MappedFileReader {
|
||||
class MainLoop : public Thread, DeviceListener {
|
||||
public:
|
||||
/**
|
||||
* Construct the main loop and create network and bus handling components.
|
||||
* Construct the main loop and create bus handling components.
|
||||
* @param opt the program options.
|
||||
* @param device the @a Device instance.
|
||||
* @param messages the @a MessageMap instance.
|
||||
* @param scanHelper the @a ScanHelper instance.
|
||||
* @param requestQueue the reference to the @a Request @a Queue.
|
||||
*/
|
||||
MainLoop(const struct options& opt, Device *device, MessageMap* messages, ScanHelper* scanHelper);
|
||||
MainLoop(const struct options& opt, Device *device, MessageMap* messages, ScanHelper* scanHelper,
|
||||
Queue<Request*>* requestQueue);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@@ -126,12 +128,6 @@ class MainLoop : public Thread, DeviceListener {
|
||||
*/
|
||||
BusHandler* getBusHandler() { return m_busHandler; }
|
||||
|
||||
/**
|
||||
* Add a client @a NetMessage to the queue.
|
||||
* @param message the client @a NetMessage to handle.
|
||||
*/
|
||||
void addMessage(NetMessage* message) { m_netQueue.push(message); }
|
||||
|
||||
// @copydoc
|
||||
void notifyDeviceData(symbol_t symbol, bool received) override;
|
||||
|
||||
@@ -146,17 +142,16 @@ class MainLoop : public Thread, DeviceListener {
|
||||
|
||||
private:
|
||||
/**
|
||||
* Decode and execute client message.
|
||||
* @param data the data string to decode (may be empty).
|
||||
* Decode and execute client request.
|
||||
* @param req the @a Request to decode.
|
||||
* @param connected set to false when the client connection shall be closed.
|
||||
* @param isHttp true for HTTP message.
|
||||
* @param settings set to the new client settings.
|
||||
* @param reqMode the @a RequestMode to use and update.
|
||||
* @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, ClientSettings* settings,
|
||||
result_t decodeRequest(Request* req, bool* connected, RequestMode* reqMode,
|
||||
string* user, bool* reload, ostringstream* ostream);
|
||||
|
||||
/**
|
||||
@@ -227,11 +222,11 @@ class MainLoop : public Thread, DeviceListener {
|
||||
/**
|
||||
* Execute the direct 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 reqMode the @a RequestMode to use and update.
|
||||
* @param ostream the @a ostringstream to format the result string to.
|
||||
* @return the result code.
|
||||
*/
|
||||
result_t executeDirect(const vector<string>& args, ClientMode* mode, ostringstream* ostream);
|
||||
result_t executeDirect(const vector<string>& args, RequestMode* reqMode, ostringstream* ostream);
|
||||
|
||||
/**
|
||||
* Execute the find command.
|
||||
@@ -245,11 +240,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 settings set to the new client settings.
|
||||
* @param reqMode the @a RequestMode to use and update.
|
||||
* @param ostream the @a ostringstream to format the result string to.
|
||||
* @return the result code.
|
||||
*/
|
||||
result_t executeListen(const vector<string>& args, ClientSettings* settings, ostringstream* ostream);
|
||||
result_t executeListen(const vector<string>& args, RequestMode* reqMode, ostringstream* ostream);
|
||||
|
||||
/**
|
||||
* Execute the state command.
|
||||
@@ -445,11 +440,8 @@ class MainLoop : public Thread, DeviceListener {
|
||||
/** the created @a BusHandler instance. */
|
||||
BusHandler* m_busHandler;
|
||||
|
||||
/** the created @a Network instance. */
|
||||
Network* m_network;
|
||||
|
||||
/** the @a NetMessage @a Queue. */
|
||||
Queue<NetMessage*> m_netQueue;
|
||||
/** the reference to the @a Request @a Queue. */
|
||||
Queue<Request*>* m_requestQueue;
|
||||
|
||||
/** the path for HTML files served by the HTTP port. */
|
||||
string m_htmlPath;
|
||||
|
||||
+15
-45
@@ -37,39 +37,6 @@ int Connection::m_ids = 0;
|
||||
#define POLLRDHUP 0
|
||||
#endif
|
||||
|
||||
bool NetMessage::add(const char* request) {
|
||||
if (request && request[0]) {
|
||||
string add = request;
|
||||
add.erase(remove(add.begin(), add.end(), '\r'), add.end());
|
||||
m_request.append(add);
|
||||
}
|
||||
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
|
||||
if (pos != string::npos) {
|
||||
if (m_isHttp) {
|
||||
pos = m_request.find("\n");
|
||||
m_request.resize(pos); // reduce to first line
|
||||
// typical first line: GET /ehp/outsidetemp HTTP/1.1
|
||||
pos = m_request.rfind(" HTTP/");
|
||||
if (pos != string::npos) {
|
||||
m_request.resize(pos); // remove "HTTP/x.x" suffix
|
||||
}
|
||||
pos = 0;
|
||||
while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
|
||||
unsigned int value1, value2;
|
||||
if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2) < 2) {
|
||||
break;
|
||||
}
|
||||
m_request[pos] = static_cast<char>(((value1&0x0f) << 4) | (value2&0x0f));
|
||||
m_request.erase(pos+1, 2);
|
||||
}
|
||||
} else if (pos+1 == m_request.length()) {
|
||||
m_request.resize(pos); // reduce to complete lines
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return m_request.length() == 0 && isListeningMode();
|
||||
}
|
||||
|
||||
|
||||
void Connection::run() {
|
||||
int ret;
|
||||
@@ -108,7 +75,7 @@ void Connection::run() {
|
||||
#endif
|
||||
|
||||
bool closed = false;
|
||||
NetMessage message(m_isHttp);
|
||||
RequestImpl req(m_isHttp);
|
||||
|
||||
while (!closed) {
|
||||
#ifdef HAVE_PPOLL
|
||||
@@ -146,7 +113,7 @@ void Connection::run() {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (newData || message.isListeningMode()) {
|
||||
if (newData || req.getMode().listenMode != lm_none) {
|
||||
char data[256];
|
||||
|
||||
if (!m_socket->isValid()) {
|
||||
@@ -165,21 +132,24 @@ void Connection::run() {
|
||||
}
|
||||
|
||||
// decode client data
|
||||
if (message.add(data)) {
|
||||
m_netQueue->push(&message);
|
||||
if (req.add(data)) {
|
||||
m_requestQueue->push(&req);
|
||||
|
||||
// wait for result
|
||||
logDebug(lf_network, "[%05d] wait for result", getID());
|
||||
string result;
|
||||
message.getResult(&result);
|
||||
bool disconnect = req.waitResponse(&result);
|
||||
|
||||
if (!m_socket->isValid()) {
|
||||
break;
|
||||
}
|
||||
m_socket->send(result.c_str(), result.size());
|
||||
if (disconnect) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (message.isDisconnect() || !m_socket->isValid()) {
|
||||
if (!m_socket->isValid()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -193,8 +163,8 @@ void Connection::run() {
|
||||
}
|
||||
|
||||
|
||||
Network::Network(const bool local, const uint16_t port, const uint16_t httpPort, Queue<NetMessage*>* netQueue)
|
||||
: Thread(), m_netQueue(netQueue), m_listening(false) {
|
||||
Network::Network(const bool local, const uint16_t port, const uint16_t httpPort, Queue<Request*>* requestQueue)
|
||||
: Thread(), m_requestQueue(requestQueue), m_listening(false) {
|
||||
m_tcpServer = new TCPServer(port, local ? "127.0.0.1" : "0.0.0.0");
|
||||
|
||||
if (m_tcpServer != nullptr && m_tcpServer->start() == 0) {
|
||||
@@ -214,9 +184,9 @@ Network::Network(const bool local, const uint16_t port, const uint16_t httpPort,
|
||||
|
||||
Network::~Network() {
|
||||
stop();
|
||||
NetMessage* netMsg;
|
||||
while ((netMsg = m_netQueue->pop()) != nullptr) {
|
||||
netMsg->setResult("ERR: shutdown", "", nullptr, 0, true);
|
||||
Request* req;
|
||||
while ((req = m_requestQueue->pop()) != nullptr) {
|
||||
req->setResult("ERR: shutdown", "", nullptr, 0, true);
|
||||
}
|
||||
while (!m_connections.empty()) {
|
||||
Connection* connection = m_connections.back();
|
||||
@@ -333,7 +303,7 @@ void Network::run() {
|
||||
if (socket == nullptr) {
|
||||
continue;
|
||||
}
|
||||
Connection* connection = new Connection(socket, isHttp, m_netQueue);
|
||||
Connection* connection = new Connection(socket, isHttp, m_requestQueue);
|
||||
string ip = socket->getIP();
|
||||
connection->start("connection");
|
||||
m_connections.push_back(connection);
|
||||
|
||||
+12
-190
@@ -23,6 +23,7 @@
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include "ebusd/request.h"
|
||||
#include "lib/ebus/datatype.h"
|
||||
#include "lib/utils/tcpsocket.h"
|
||||
#include "lib/utils/queue.h"
|
||||
@@ -35,188 +36,9 @@ namespace ebusd {
|
||||
* The TCP and HTTP client request handling.
|
||||
*/
|
||||
|
||||
/** Forward declaration for @a Connection. */
|
||||
class Connection;
|
||||
|
||||
/** the possible client modes. */
|
||||
enum ClientMode {
|
||||
cm_normal, //!< normal mode
|
||||
cm_listen, //!< listening mode
|
||||
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
|
||||
bool listenWithUnknown; //!< include unknown messages in listen mode
|
||||
bool listenOnlyUnknown; //!< only print unknown messages in listen mode
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for data/message transfer between @a Connection and @a MainLoop.
|
||||
*/
|
||||
class NetMessage {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param isHttp whether this is a HTTP message.
|
||||
*/
|
||||
explicit NetMessage(bool isHttp)
|
||||
: m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listenSince(0) {
|
||||
m_settings.mode = cm_normal;
|
||||
m_settings.format = OF_NONE;
|
||||
m_settings.listenWithUnknown = false;
|
||||
m_settings.listenOnlyUnknown = false;
|
||||
pthread_mutex_init(&m_mutex, nullptr);
|
||||
pthread_cond_init(&m_cond, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~NetMessage() {
|
||||
m_resultSet = true;
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_cond);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param src the object to copy from.
|
||||
*/
|
||||
NetMessage(const NetMessage& src);
|
||||
|
||||
|
||||
public:
|
||||
/**
|
||||
* Add request data received from the client.
|
||||
* @param request the request data from the client.
|
||||
* @return true when the request is complete and the response shall be prepared.
|
||||
*/
|
||||
bool add(const char* request);
|
||||
|
||||
/**
|
||||
* Return whether this is a HTTP message.
|
||||
* @return whether this is a HTTP message.
|
||||
*/
|
||||
bool isHttp() const { return m_isHttp; }
|
||||
|
||||
/**
|
||||
* Return the request string.
|
||||
* @return the request string.
|
||||
*/
|
||||
const string& getRequest() const { return m_request; }
|
||||
|
||||
/**
|
||||
* Return the current user name.
|
||||
* @return the current user name.
|
||||
*/
|
||||
const string& getUser() const { return m_user; }
|
||||
|
||||
/**
|
||||
* Wait for the result being set and return the result string.
|
||||
* @param result the variable in which to store the result string.
|
||||
*/
|
||||
void getResult(string* result) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
if (!m_resultSet) {
|
||||
pthread_cond_wait(&m_cond, &m_mutex);
|
||||
}
|
||||
m_request.clear();
|
||||
*result = m_result;
|
||||
m_result.clear();
|
||||
m_resultSet = false;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the result string and notify the waiting thread.
|
||||
* @param result the result string.
|
||||
* @param user the new user name.
|
||||
* @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, ClientSettings* settings, time_t listenUntil,
|
||||
bool disconnect) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_result = result;
|
||||
m_user = user;
|
||||
m_disconnect = disconnect;
|
||||
if (settings) {
|
||||
m_settings = *settings;
|
||||
}
|
||||
m_listenSince = listenUntil;
|
||||
m_resultSet = true;
|
||||
pthread_cond_signal(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client settings.
|
||||
* @param listenSince set listening to the specified start time from which to add updates (inclusive).
|
||||
* @return the client settings.
|
||||
*/
|
||||
ClientSettings getSettings(time_t* listenSince = nullptr) {
|
||||
if (listenSince) {
|
||||
*listenSince = m_listenSince;
|
||||
}
|
||||
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_settings.mode == cm_listen || m_settings.mode == cm_direct; }
|
||||
|
||||
/**
|
||||
* Return whether the client shall be disconnected.
|
||||
* @return true when the client shall be disconnected.
|
||||
*/
|
||||
bool isDisconnect() { return m_disconnect; }
|
||||
|
||||
|
||||
private:
|
||||
/** whether this is a HTTP message. */
|
||||
const bool m_isHttp;
|
||||
|
||||
/** the request string. */
|
||||
string m_request;
|
||||
|
||||
/** the current user name. */
|
||||
string m_user;
|
||||
|
||||
/** whether the result was already set. */
|
||||
bool m_resultSet;
|
||||
|
||||
/** the result string. */
|
||||
string m_result;
|
||||
|
||||
/** set to true when the client shall be disconnected. */
|
||||
bool m_disconnect;
|
||||
|
||||
/** mutex variable for exclusive lock. */
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
/** condition variable for exclusive lock. */
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
/** the client settings. */
|
||||
ClientSettings m_settings;
|
||||
|
||||
/** start timestamp of listening update. */
|
||||
time_t m_listenSince;
|
||||
};
|
||||
|
||||
/**
|
||||
* class connection which handle client and baseloop communication.
|
||||
* Instance of a connected client, either TCP or HTTP.
|
||||
*/
|
||||
class Connection : public Thread {
|
||||
public:
|
||||
@@ -224,10 +46,10 @@ class Connection : public Thread {
|
||||
* Constructor.
|
||||
* @param socket the @a TCPSocket for communication.
|
||||
* @param isHttp whether this is a HTTP message.
|
||||
* @param netQueue the reference to the @a NetMessage @a Queue.
|
||||
* @param requestQueue the reference to the @a Request @a Queue.
|
||||
*/
|
||||
Connection(TCPSocket* socket, const bool isHttp, Queue<NetMessage*>* netQueue)
|
||||
: Thread(), m_isHttp(isHttp), m_socket(socket), m_netQueue(netQueue), m_endedAt(0) {
|
||||
Connection(TCPSocket* socket, const bool isHttp, Queue<Request*>* requestQueue)
|
||||
: Thread(), m_isHttp(isHttp), m_socket(socket), m_requestQueue(requestQueue), m_endedAt(0) {
|
||||
m_id = ++m_ids;
|
||||
}
|
||||
|
||||
@@ -267,8 +89,8 @@ class Connection : public Thread {
|
||||
/** the @a TCPSocket for communication. */
|
||||
TCPSocket* m_socket;
|
||||
|
||||
/** the reference to the @a NetMessage @a Queue. */
|
||||
Queue<NetMessage*>* m_netQueue;
|
||||
/** the reference to the @a Request @a Queue. */
|
||||
Queue<Request*>* m_requestQueue;
|
||||
|
||||
/** notification object for shutdown procedure. */
|
||||
Notify m_notify;
|
||||
@@ -284,7 +106,7 @@ class Connection : public Thread {
|
||||
};
|
||||
|
||||
/**
|
||||
* class network which listening on tcp socket for incoming connections.
|
||||
* Handler for all TCP and HTTP client connections and registry of active connections.
|
||||
*/
|
||||
class Network : public Thread {
|
||||
public:
|
||||
@@ -293,9 +115,9 @@ class Network : public Thread {
|
||||
* @param local true to accept connections only for local host.
|
||||
* @param port the port to listen for command line connections.
|
||||
* @param httpPort the port to listen for HTTP connections, or 0.
|
||||
* @param netQueue the reference to the @a NetMessage @a Queue.
|
||||
* @param requestQueue the reference to the @a Request @a Queue.
|
||||
*/
|
||||
Network(const bool local, const uint16_t port, const uint16_t httpPort, Queue<NetMessage*>* netQueue);
|
||||
Network(const bool local, const uint16_t port, const uint16_t httpPort, Queue<Request*>* requestQueue);
|
||||
|
||||
/**
|
||||
* destructor.
|
||||
@@ -317,8 +139,8 @@ class Network : public Thread {
|
||||
/** the list of active @a Connection instances. */
|
||||
list<Connection*> m_connections;
|
||||
|
||||
/** the reference to the @a NetMessage @a Queue. */
|
||||
Queue<NetMessage*>* m_netQueue;
|
||||
/** the reference to the @a Request @a Queue. */
|
||||
Queue<Request*>* m_requestQueue;
|
||||
|
||||
/** the command line @a TCPServer instance. */
|
||||
TCPServer* m_tcpServer;
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2023 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "ebusd/request.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <cstring>
|
||||
#include "lib/utils/log.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
RequestImpl::RequestImpl(bool isHttp)
|
||||
: Request(), m_isHttp(isHttp), m_resultSet(false), m_disconnect(false), m_listenSince(0) {
|
||||
m_mode.listenMode = lm_none;
|
||||
m_mode.format = OF_NONE;
|
||||
m_mode.listenWithUnknown = false;
|
||||
m_mode.listenOnlyUnknown = false;
|
||||
pthread_mutex_init(&m_mutex, nullptr);
|
||||
pthread_cond_init(&m_cond, nullptr);
|
||||
}
|
||||
|
||||
RequestImpl::~RequestImpl() {
|
||||
m_resultSet = true;
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_cond_destroy(&m_cond);
|
||||
}
|
||||
|
||||
bool RequestImpl::add(const char* request) {
|
||||
if (request && request[0]) {
|
||||
string add = request;
|
||||
add.erase(remove(add.begin(), add.end(), '\r'), add.end());
|
||||
m_request.append(add);
|
||||
}
|
||||
size_t pos = m_request.find(m_isHttp ? "\n\n" : "\n");
|
||||
if (pos != string::npos) {
|
||||
if (m_isHttp) {
|
||||
pos = m_request.find("\n");
|
||||
m_request.resize(pos); // reduce to first line
|
||||
// typical first line: GET /ehp/outsidetemp HTTP/1.1
|
||||
pos = m_request.rfind(" HTTP/");
|
||||
if (pos != string::npos) {
|
||||
m_request.resize(pos); // remove "HTTP/x.x" suffix
|
||||
}
|
||||
pos = 0;
|
||||
while ((pos=m_request.find('%', pos)) != string::npos && pos+2 <= m_request.length()) {
|
||||
unsigned int value1, value2;
|
||||
if (sscanf("%1x%1x", m_request.c_str()+pos+1, &value1, &value2) < 2) {
|
||||
break;
|
||||
}
|
||||
m_request[pos] = static_cast<char>(((value1&0x0f) << 4) | (value2&0x0f));
|
||||
m_request.erase(pos+1, 2);
|
||||
}
|
||||
} else if (pos+1 == m_request.length()) {
|
||||
m_request.resize(pos); // reduce to complete lines
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return m_request.length() == 0 && m_mode.listenMode != lm_none;
|
||||
}
|
||||
|
||||
void RequestImpl::split(vector<string>* args) {
|
||||
string token, previous;
|
||||
istringstream stream(m_request);
|
||||
char escaped = 0;
|
||||
|
||||
char delim = ' ';
|
||||
while (getline(stream, token, delim)) {
|
||||
if (!m_isHttp) {
|
||||
if (escaped) {
|
||||
args->pop_back();
|
||||
if (token.length() > 0 && token[token.length()-1] == escaped) {
|
||||
token.erase(token.length() - 1, 1);
|
||||
escaped = 0;
|
||||
}
|
||||
token = previous + " " + token;
|
||||
} else if (token.length() == 0) { // allow multiple space chars for a single delimiter
|
||||
continue;
|
||||
} else if (token[0] == '"' || token[0] == '\'') {
|
||||
escaped = token[0];
|
||||
token.erase(0, 1);
|
||||
if (token.length() > 0 && token[token.length()-1] == escaped) {
|
||||
token.erase(token.length() - 1, 1);
|
||||
escaped = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
args->push_back(token);
|
||||
previous = token;
|
||||
if (m_isHttp) {
|
||||
delim = (args->size() == 1) ? '?' : '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RequestImpl::waitResponse(string* result) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
|
||||
if (!m_resultSet) {
|
||||
pthread_cond_wait(&m_cond, &m_mutex);
|
||||
}
|
||||
m_request.clear();
|
||||
*result = m_result;
|
||||
m_result.clear();
|
||||
m_resultSet = false;
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return m_disconnect;
|
||||
}
|
||||
|
||||
void RequestImpl::setResult(const string& result, const string& user, RequestMode* mode, time_t listenUntil,
|
||||
bool disconnect) {
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_result = result;
|
||||
m_user = user;
|
||||
m_disconnect = disconnect;
|
||||
if (mode) {
|
||||
m_mode = *mode;
|
||||
}
|
||||
m_listenSince = listenUntil;
|
||||
m_resultSet = true;
|
||||
pthread_cond_signal(&m_cond);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
} // namespace ebusd
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* ebusd - daemon for communication with eBUS heating systems.
|
||||
* Copyright (C) 2023 John Baier <ebusd@ebusd.eu>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EBUSD_REQUEST_H_
|
||||
#define EBUSD_REQUEST_H_
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "lib/ebus/datatype.h"
|
||||
#include "lib/utils/queue.h"
|
||||
#include "lib/utils/notify.h"
|
||||
#include "lib/utils/thread.h"
|
||||
#include "lib/utils/log.h"
|
||||
|
||||
namespace ebusd {
|
||||
|
||||
/** \file ebusd/request.h
|
||||
* Abstraction of ebusd client requests.
|
||||
*/
|
||||
|
||||
/** the request listen mode. */
|
||||
enum ListenMode {
|
||||
lm_none, //!< normal mode (no listening)
|
||||
lm_listen, //!< listening mode
|
||||
lm_direct, //!< direct mode
|
||||
};
|
||||
|
||||
/**
|
||||
* Request mode info.
|
||||
*/
|
||||
struct RequestMode {
|
||||
ListenMode listenMode; //!< whether in listening or direct mode
|
||||
OutputFormat format; //!< the output format settings for listen mode
|
||||
bool listenWithUnknown; //!< include unknown messages in listen/direct mode
|
||||
bool listenOnlyUnknown; //!< only print unknown messages in listen/direct mode
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstract class for request/response.
|
||||
*/
|
||||
class Request {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Request() { }
|
||||
|
||||
/**
|
||||
* Add request data from the client.
|
||||
* @param request the request data from the client.
|
||||
* @return true when the request is complete and the response shall be prepared.
|
||||
*/
|
||||
virtual bool add(const char* request) = 0;
|
||||
|
||||
/**
|
||||
* @return whether the request is still empty.
|
||||
*/
|
||||
virtual bool empty() const = 0;
|
||||
|
||||
/**
|
||||
* Split the request into arguments.
|
||||
* @param args the @a vector to push the arguments to.
|
||||
*/
|
||||
virtual void split(vector<string>* args) = 0;
|
||||
|
||||
/**
|
||||
* Return whether this is a HTTP request.
|
||||
* @return whether this is a HTTP request.
|
||||
*/
|
||||
virtual bool isHttp() const = 0;
|
||||
|
||||
/**
|
||||
* Log the request or the given response in debug level.
|
||||
*/
|
||||
virtual void log(const string* response = nullptr) const = 0;
|
||||
|
||||
/**
|
||||
* Return the current user name.
|
||||
* @return the current user name.
|
||||
*/
|
||||
virtual const string& getUser() const = 0;
|
||||
|
||||
/**
|
||||
* Wait for the response being set and return the result string.
|
||||
* @param result the variable in which to store the result string.
|
||||
* @return true when the client shall be disconnected.
|
||||
*/
|
||||
virtual bool waitResponse(string* result) = 0;
|
||||
|
||||
/**
|
||||
* Set the result string and notify a waiting thread.
|
||||
* @param result the result string.
|
||||
* @param user the new user name.
|
||||
* @param newMode the new @a RequestMode.
|
||||
* @param listenUntil the end time to which to updates were added (exclusive).
|
||||
* @param disconnect true when the client shall be disconnected.
|
||||
*/
|
||||
virtual void setResult(const string& result, const string& user, RequestMode* newMode, time_t listenUntil,
|
||||
bool disconnect) = 0;
|
||||
|
||||
/**
|
||||
* Return the @a RequestMode.
|
||||
* @param listenSince set listening to the specified start time from which to add updates (inclusive).
|
||||
* @return the @a RequestMode.
|
||||
*/
|
||||
virtual RequestMode getMode(time_t* listenSince = nullptr) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default @a Request implementation.
|
||||
*/
|
||||
class RequestImpl : public Request {
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param isHttp whether this is a HTTP request.
|
||||
*/
|
||||
explicit RequestImpl(bool isHttp);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~RequestImpl();
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* Hidden copy constructor.
|
||||
* @param src the object to copy from.
|
||||
*/
|
||||
RequestImpl(const RequestImpl& src);
|
||||
|
||||
|
||||
public:
|
||||
// @copydoc
|
||||
bool add(const char* request) override;
|
||||
|
||||
// @copydoc
|
||||
bool empty() const override { return m_request.empty(); }
|
||||
|
||||
// @copydoc
|
||||
void split(vector<string>* args) override;
|
||||
|
||||
// @copydoc
|
||||
bool isHttp() const override { return m_isHttp; }
|
||||
|
||||
// @copydoc
|
||||
void log(const string* response = nullptr) const override {
|
||||
if (response) {
|
||||
if (response->length() > 100) {
|
||||
logDebug(lf_main, "<<< %s ...", response->substr(0, 100).c_str());
|
||||
} else {
|
||||
logDebug(lf_main, "<<< %s", response->c_str());
|
||||
}
|
||||
} else {
|
||||
logDebug(lf_main, ">>> %s", m_request.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// @copydoc
|
||||
const string& getUser() const override { return m_user; }
|
||||
|
||||
// @copydoc
|
||||
bool waitResponse(string* result) override;
|
||||
|
||||
// @copydoc
|
||||
void setResult(const string& result, const string& user, RequestMode* mode, time_t listenUntil,
|
||||
bool disconnect) override;
|
||||
|
||||
// @copydoc
|
||||
RequestMode getMode(time_t* listenSince = nullptr) override {
|
||||
if (listenSince) {
|
||||
*listenSince = m_listenSince;
|
||||
}
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
/** whether this is a HTTP message. */
|
||||
const bool m_isHttp;
|
||||
|
||||
/** the request string. */
|
||||
string m_request;
|
||||
|
||||
/** the current user name. */
|
||||
string m_user;
|
||||
|
||||
/** whether the result was already set. */
|
||||
bool m_resultSet;
|
||||
|
||||
/** the result string. */
|
||||
string m_result;
|
||||
|
||||
/** set to true when the client shall be disconnected. */
|
||||
bool m_disconnect;
|
||||
|
||||
/** mutex variable for exclusive lock. */
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
/** condition variable for exclusive lock. */
|
||||
pthread_cond_t m_cond;
|
||||
|
||||
/** the @a RequestMode. */
|
||||
RequestMode m_mode;
|
||||
|
||||
/** start timestamp of listening update. */
|
||||
time_t m_listenSince;
|
||||
};
|
||||
|
||||
} // namespace ebusd
|
||||
|
||||
#endif // EBUSD_REQUEST_H_
|
||||
Reference in New Issue
Block a user