aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Littow <sami.littow@qt.io>2023-01-11 11:16:48 +0200
committerSami Littow <sami.littow@qt.io>2023-01-11 11:16:48 +0200
commitd336134912de78c78594ab674b246d0a520889f6 (patch)
treebd5660a33bd4a7a8803d998ff55b185cf04415d4
parentcd8509d3b5c91d93b16b3f6da2e760632cb49e67 (diff)
Preliminary Squish support
-rw-r--r--CHANGELOG5
-rw-r--r--CMakePresets.json35
-rw-r--r--include/commonsetup.h35
-rw-r--r--include/httpclient.h5
-rw-r--r--include/licenser.h2
-rw-r--r--include/utils.h3
-rw-r--r--qtlicd.ini9
-rw-r--r--qtlicensetool/qtlicensetool.cpp45
-rw-r--r--qtlicensetool/qtlicensetool.h4
-rw-r--r--src/clienthandler.cpp19
-rw-r--r--src/daemon_clients/clienthandler.h10
-rw-r--r--src/daemon_clients/clitoolhandler.h13
-rw-r--r--src/daemon_clients/cocohandler.h3
-rw-r--r--src/daemon_clients/squishhandler.h55
-rw-r--r--src/daemon_clients/squishidehandler.h3
-rw-r--r--src/httpclient.cpp31
-rw-r--r--src/jsonhandler.cpp2
-rw-r--r--src/licenser.cpp94
-rw-r--r--src/tcpserver.cpp6
-rw-r--r--src/utils.cpp32
20 files changed, 243 insertions, 168 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3a43a14..b16aee9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -37,5 +37,8 @@ Changes in 2.0.4:
Changes in 2.1.0:
- Floating license support added (Squish)
- Daemon name 'licd' changed to 'qtlicd'
-- Concept of "long-term" changed to "permanent"
+- Concept of "long-term" renamed to "permanent"
- Daemon architecture changed towards more modular approach
+- Fixed a bug with SSL support
+- Added HW ID calculation if empty (hw_id now empty by default in qtlicd.ini)
+- Removed possibility to override license server address from CLI
diff --git a/CMakePresets.json b/CMakePresets.json
index ba0884e..d4d9f74 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -1,4 +1,4 @@
-{
+{
"version": 3,
"configurePresets": [
{
@@ -7,9 +7,7 @@
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"installDir": "${sourceDir}/deploy/${presetName}",
- "cacheVariables": {
-
- },
+ "cacheVariables": {},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
@@ -55,16 +53,25 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
+ },
+ {
+ "name": "arm64",
+ "displayName": "Configure preset using toolchain file",
+ "description": "Sets Ninja generator, build and install directory",
+ "generator": "Ninja",
+ "binaryDir": "${sourceDir}/out/build/${presetName}",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "CMAKE_TOOLCHAIN_FILE": "",
+ "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
+ }
}
],
-
- "buildPresets":
- [
- {
- "name": "build",
- "configurePreset": "x64-debug",
- "jobs": 2
- }
+ "buildPresets": [
+ {
+ "name": "build",
+ "configurePreset": "x64-debug",
+ "jobs": 2
+ }
]
-
-}
+} \ No newline at end of file
diff --git a/include/commonsetup.h b/include/commonsetup.h
index 65a78e3..92d27bb 100644
--- a/include/commonsetup.h
+++ b/include/commonsetup.h
@@ -19,9 +19,10 @@
#define DAEMON_VERSION_CMD "daemon_version"
#define RESERVATION_QUERY_CMD "reservation_query"
#define LICENSE_REQUEST_CMD "license"
-#define LONGTERM_REQUEST_CMD "longterm"
+#define PERMANENT_REQUEST_CMD "permanent"
#define OP_ADD_RESERVATION "add"
#define OP_REMOVE_RESERVATION "remove"
+#define OP_QA_RELEASE_RESERVATION "release"
#define QTLICENSETOOL_APP_NAME "clitool"
#define SQUISH_IDE_APP_NAME "squish-ide"
@@ -50,27 +51,27 @@
struct License {
uint64_t last_timestamp = 0; // |
uint64_t current_timestamp = 0; // | For internal use only, not in server resp JSON
- uint64_t expiry_epoch = 0; // _|
- uint16_t leeway_hours = 0;
- std::string message;
+ uint64_t expiry_epoch = 0; // |
bool status = false;
- std::string expiry_date;
- std::string operation;
+ std::string message;
+ std::string user_id;
std::string license_key;
std::string license_id;
+ std::string expiry_date;
std::string reservation_id;
- std::string parent_reservation_id; // TODO Coming with qa tools: Check with server end!
- std::string user_id;
+ std::string parentReservation;
+ uint16_t leeway_hours = 0;
};
enum RequestReply {
- e_bad_request = -1,
- e_got_response = 0,
- e_license_granted = 1,
- e_license_rejected = 2,
- e_no_conn_leeway = 3,
- e_license_pool_full = 4,
- e_bad_connection = 5
+ e_bad_request = -1,
+ e_got_response = 0,
+ e_license_granted = 1,
+ e_license_rejected = 2,
+ e_no_conn_leeway = 3,
+ e_license_pool_full = 4,
+ e_no_permanent_to_release = 5,
+ e_bad_connection = 6
};
enum class RequestType {
@@ -97,7 +98,7 @@ enum class ClientType {
// Struct to store request info
struct RequestInfo {
uint16_t socketId;
- RequestType type = RequestType::no_request;
+ RequestType reqType = RequestType::no_request;
ClientType client;
uint16_t updateIntervalSecs;
std::string licenseFile;
@@ -112,7 +113,7 @@ struct RequestInfo {
std::string serverAddr;
uint64_t startTimestamp; // used by QA-Tools only
uint64_t stopTimestamp = 0; // used by QA-Tools only
- std::string runnerType; // 'tester' | 'exe', used by QA-Tools only
+ std::string runnerType; // "qa_tester" || "qa_exe", used by QA-Tools only
std::string parentReservationId; // used by QA-Tools only
};
diff --git a/include/httpclient.h b/include/httpclient.h
index 6ee1f86..b1a63c1 100644
--- a/include/httpclient.h
+++ b/include/httpclient.h
@@ -26,7 +26,6 @@
struct HttpRequest {
std::string payload;
std::string url;
- std::string authKey;
std::string reply;
curl_slist *headers = nullptr;
};
@@ -40,7 +39,7 @@ class HttpClient
public:
explicit HttpClient(const std::string &serverUrl,
const std::string &requestAccessPoint,
- const std::string &longtermAccessPoint,
+ const std::string &permanentccessPoint,
const std::string &versionAccessPoint);
~HttpClient() {}
@@ -50,7 +49,7 @@ public:
private:
std::string m_serverUrl;
std::string m_requestAccessPoint;
- std::string m_longtermAccessPoint;
+ std::string m_permanentAccessPoint;
std::string m_versionAccessPoint;
std::string m_userAgent = "License daemon / ";
std::string m_lastError;
diff --git a/include/licenser.h b/include/licenser.h
index 449ee9a..1f7256d 100644
--- a/include/licenser.h
+++ b/include/licenser.h
@@ -56,7 +56,7 @@ private:
std::string askServerVersion();
std::string getDaemonVersion();
int checkReportsDue();
- void clientDisconnected(int socketId);
+ void removeClient(int socketId);
void setHwId();
LicdSetup *settings;
diff --git a/include/utils.h b/include/utils.h
index 13a4e6c..a215ffd 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -75,8 +75,9 @@ std::string epochToString(time_t epochTime, const char* format = "%Y-%m-%d %H:%M
time_t stringToEpoch(const char* theTime, const char* format = "%Y-%m-%d %H:%M:%S");
uint64_t getTimestampNow();
-// Find out host OS
+// System utils
std::string getOsName();
+std::string getSystemHwInfoString();
// Swap endian of any data
template <typename T> T swapEndian(T val)
diff --git a/qtlicd.ini b/qtlicd.ini
index c9ee56f..b7ae804 100644
--- a/qtlicd.ini
+++ b/qtlicd.ini
@@ -26,7 +26,7 @@ reservation_access_point=/api/v2/reservations
# long-term_access_point
# License server REST access point for long-term license reservation requests
# Type: string
-long-term_access_point=/api/v2/reservations/long-term
+permanent_access_point=/api/v2/reservations/long-term
###################
# version_query_access_point
# License server REST access point for version query requests
@@ -42,7 +42,7 @@ moc_renewal_interval=24
# squish_report_interval
# Duration (in secs) between update calls to the server while Squish is working.
# Type: int
-squish_report_interval=300
+squish_report_interval=5
###################
# coco_update_interval
# Duration (in secs) between update calls to the server while Coco is working.
@@ -53,9 +53,10 @@ coco_update_interval=5
tcp_listening_port=60000
###################
# hw_id
-# Calculated hardware ID of the host machine. Goes obsolete as soon it can be calculated on the fly
+# Calculated hardware ID of the host machine. This is empty by default, will be calculated in the first daemon run.
+# Can be recalculated by deleting the value (making it empty again) and restarting the daemon
# Type: string
-hw_id=c31aa37762ef3bb84e09eeea0bc9bccb6b96a81b2657b1a356ec51709975a5ea
+hw_id=
# user_settings_tag
# Tag under which user settings should reside
# Type: string
diff --git a/qtlicensetool/qtlicensetool.cpp b/qtlicensetool/qtlicensetool.cpp
index 75f0343..f0e6105 100644
--- a/qtlicensetool/qtlicensetool.cpp
+++ b/qtlicensetool/qtlicensetool.cpp
@@ -25,10 +25,10 @@ int main(int argc, char *argv[])
}
// Then those requiring connection
- if (action == "--longterm" || action == "-L") {
+ if (action == "--permanent" || action == "-p") {
// Override setup with cmd-line args:
overrideSetup(&setup, argc, argv);
- doLongtermRequest(&setup);
+ doPermanentRequest(&setup);
} else if (action == "--serverversion" || action == "-S") {
askStatus(SERVER_VERSION_CMD, &setup);
} else if (action == "--daemonversion" || action == "-D") {
@@ -75,23 +75,23 @@ void overrideSetup(LicdSetup *setup, int argc, char *argv[])
{
// Pick up the cmd-line switches: Start looping args from index 1,
// as first one is the command itself
- bool longterm = false;
+ bool permanent = false;
for (int i = 1; i < argc; i++) {
std::string sw = utils::trimStr(argv[i]);
std::string val = "";
- if (sw == "-L" || sw == "--longterm") {
- longterm = true;
+ if (sw == "-p" || sw == "--permanent") {
+ permanent = true;
continue;
}
- if (longterm) {
- // Longterm operation (add|remove) has to come right after the -L switch, not later
+ if (permanent) {
+ // Permanent operation (add|remove) has to come right after the -P switch, not later
if (sw == OP_ADD_RESERVATION || sw == OP_REMOVE_RESERVATION) {
setup->set("operation", sw);
- longterm = false;
+ permanent = false;
continue;
}
else {
- errorAndExit("Invalid longterm operation");
+ errorAndExit("Invalid operation for permanen license request");
}
}
@@ -120,14 +120,6 @@ void overrideSetup(LicdSetup *setup, int argc, char *argv[])
}
setup->set("licd_addr", val.substr(0, colPos));
setup->set("licd_port", val.substr(colPos+1));
- } else if (sw == "-l") {
- size_t colPos = val.find(':');
- if (colPos == std::string::npos) {
- errorAndExit("Invalid license server address: Must be in form <url>:<port>");
- }
- setup->set("license_server_addr", val.substr(0, colPos));
- setup->set("license_server_port", val.substr(colPos + 1));
-
} else {
std::string error = "Invalid argument:" + sw;
errorAndExit(error);
@@ -135,11 +127,11 @@ void overrideSetup(LicdSetup *setup, int argc, char *argv[])
}
}
-int doLongtermRequest(LicdSetup *setup)
+int doPermanentRequest(LicdSetup *setup)
{
std::string operation = setup->get("operation");
if (operation != OP_ADD_RESERVATION && operation != OP_REMOVE_RESERVATION) {
- std::string error = "Invalid operation \"" + operation;
+ std::string error = "Invalid operation \"" + operation + "\"";
error += "\"";
errorAndExit(error);
}
@@ -150,17 +142,12 @@ int doLongtermRequest(LicdSetup *setup)
// Ready to build the request
std::stringstream request;
- request << LONGTERM_REQUEST_CMD << " " << setup->get("operation")
+ request << PERMANENT_REQUEST_CMD << " " << setup->get("operation")
<< " -u " << setup->get("user_id")
<< " -i " << setup->get("license_id")
<< " -e " << setup->get("user_email")
<< " -a " << QTLICENSETOOL_APP_NAME
<< " -v " << QTLICENSETOOL_VERSION;
- if (!setup->get("license_server_addr").empty()) {
- // Add optional license server URL if specified
- request << " -l " << setup->get("license_server_addr")
- << ":" << setup->get("license_server_port");
- }
// Connect and send/receive the request
TcpClient tcp(setup->get("licd_addr"), daemonPort);
@@ -198,8 +185,8 @@ void helpAndExit()
<< " -S or --serverversion : Prints out License Server version\n"
<< " -D or --daemonversion : Prints out the License Service (daemon) version\n"
<< " -r or --reservation : Prints out the list of active reservations\n"
- << " -L or --longterm : Longterm reservation (add or remove)\n"
- << " For longterm usage ('-L' or '--longterm'), you must tell which operation to do:\n"
+ << " -p or --permanent : Request permanent reservation (add or remove)\n"
+ << " For permanent request ('-P' or '--peramanent'), you must tell which operation to do:\n"
<< " add|remove <--- Either one needs to be there\n"
<< " Optionat parameters which override [default| section settings:\n"
<< " -d = Full license daemon address and port separated by ':'\n"
@@ -207,8 +194,8 @@ void helpAndExit()
<< " -i = Your Qt license ID number (must be an int)\n"
<< " -l = License server address and port separated by ':'\n"
<< " Example:\n"
- << " > qtlicensetool --longterm add : Make a long-term license reservation\n"
- << " > qtlicensetool -L add -i 462412 : Same as above, but using different license ID\n"
+ << " > qtlicensetool --permanent add : Make a permanent license reservation\n"
+ << " > qtlicensetool -P add -i 462412 : Same as above, but using different license ID\n"
<< " > qtlicensetool --daemonversion : Prints out a daemon version number\n";
exit(EXIT_SUCCESS);
}
diff --git a/qtlicensetool/qtlicensetool.h b/qtlicensetool/qtlicensetool.h
index c92c33c..8a88560 100644
--- a/qtlicensetool/qtlicensetool.h
+++ b/qtlicensetool/qtlicensetool.h
@@ -41,13 +41,13 @@ enum qt_tool_action_type {
#include "commonsetup.h"
#include "licdsetup.h"
-#define APP_NAME "Qt long-term license CLI"
+#define APP_NAME "Qt licensing CLI"
#define BUFFER_SIZE 1024
int main(int argc, char *argv[]);
void showVersion();
int askStatus(const std::string &statusRequest, LicdSetup *setup);
-int doLongtermRequest(LicdSetup *setup);
+int doPermanentRequest(LicdSetup *setup);
void overrideSetup(LicdSetup *setup, int argc, char *argv[]);
void errorAndExit(const std::string &reason = "");
void helpAndExit();
diff --git a/src/clienthandler.cpp b/src/clienthandler.cpp
index 789176b..c60d730 100644
--- a/src/clienthandler.cpp
+++ b/src/clienthandler.cpp
@@ -44,27 +44,28 @@ bool ClientHandler::checkLicenseExpiryTime(std::string &reply)
int ClientHandler::parseRequest() {
// First find out the command (and operation for longterm case)
+
std::string cmd = utils::trimStr(params[0]);
- m_request.type = RequestType::no_request;
+ m_request.reqType = RequestType::no_request;
if (cmd == LICENSE_REQUEST_CMD) {
- m_request.type = RequestType::license_request;
- } else if (cmd == LONGTERM_REQUEST_CMD) {
- m_request.type = RequestType::long_term_request;
+ m_request.reqType = RequestType::license_request;
+ } else if (cmd.substr(0, std::string(PERMANENT_REQUEST_CMD).length()) == PERMANENT_REQUEST_CMD) {
+ m_request.reqType = RequestType::long_term_request;
// find either 'add' or 'remove'
- std::string op = utils::trimStr(cmd.substr(8, cmd.length() -1));
+ std::string op = utils::trimStr(cmd.substr(std::string(PERMANENT_REQUEST_CMD).length(), cmd.length() -1));
if (op != OP_ADD_RESERVATION && op != OP_REMOVE_RESERVATION) {
- std::cout << "Invalid longterm operation: " << op;
+ std::cout << "Invalid operation for permanent request: " << op;
return e_bad_request;
}
m_request.operation = op;
} else if (cmd == SERVER_VERSION_CMD) {
- m_request.type = RequestType::server_version;
+ m_request.reqType = RequestType::server_version;
buildRequestJson();
return 0;
} else if (cmd == DAEMON_VERSION_CMD) {
- m_request.type = RequestType::daemon_version;
+ m_request.reqType = RequestType::daemon_version;
} else if (cmd == RESERVATION_QUERY_CMD) {
- m_request.type = RequestType::reservation_query;
+ m_request.reqType = RequestType::reservation_query;
} else {
std::cout << "Invalid command: " << cmd << std::endl;
return e_bad_request;
diff --git a/src/daemon_clients/clienthandler.h b/src/daemon_clients/clienthandler.h
index 1181294..695847e 100644
--- a/src/daemon_clients/clienthandler.h
+++ b/src/daemon_clients/clienthandler.h
@@ -21,8 +21,6 @@ class ClientHandler
{ }
virtual ~ClientHandler()
{ }
- // If this client is using a floating model, it needs to be cached
- // (Squish, Coco - Socket is alive until client stops working): Set this to true
std::vector<std::string> params;
@@ -30,15 +28,17 @@ class ClientHandler
virtual bool isLicenseRequestDue() = 0;
virtual int parseAndSaveResponse(std::string &response) = 0;
virtual void buildRequestJson() = 0;
+ virtual void prepareRelease() { return; }
+ virtual void resetTimer() { return; }
bool hasFloatingLicense() { return m_floatingLicense; }
+ bool hasParent() { return m_hasParent; }
void updateLicense(const std::string &responseJson);
int parseRequest();
RequestInfo getRequest() {return m_request;}
int getSocketId() { return m_request.socketId; }
- RequestType getRequestType() { return m_request.type; }
+ RequestType getRequestType() { return m_request.reqType; }
int getClientType() { return (int)m_request.client; }
- virtual void release() { return; }
protected:
License m_license;
@@ -46,6 +46,7 @@ class ClientHandler
LicdSetup m_settings;;
uint64_t m_updateInterval;
bool m_floatingLicense = false;
+ bool m_hasParent = false;
bool checkLicenseExpiryTime(std::string &reply);
bool checkLeewayTime(std::string &reply);
@@ -57,6 +58,7 @@ static std::map<RequestReply, std::string> replyString {
{e_license_rejected, "No valid license acquired"},
{e_no_conn_leeway, "License granted with warning: No server connection. Leeway time left: "},
{e_license_pool_full, "All licenses in use. No more license available on the server."},
+ {e_no_permanent_to_release, "No permanent reservations available to be released"},
{e_bad_connection, "No connection to server. Try again later."}
};
diff --git a/src/daemon_clients/clitoolhandler.h b/src/daemon_clients/clitoolhandler.h
index a63dd40..c9446d1 100644
--- a/src/daemon_clients/clitoolhandler.h
+++ b/src/daemon_clients/clitoolhandler.h
@@ -19,10 +19,11 @@ class CliToolHandler : public virtual ClientHandler {
void buildRequestJson() override
{
- if (m_request.type == RequestType::server_version) {
+ if (m_request.reqType == RequestType::server_version) {
m_request.payload = "";
return;
}
+ // Permanent operation:
std::stringstream pay;
pay << "{";
pay<< "\"license_number\":" << "\"" << m_request.licenseId << "\",";
@@ -36,22 +37,22 @@ class CliToolHandler : public virtual ClientHandler {
{
JsonHandler json(response);
std::stringstream ss;
- std::cout << json.dump(4);
- if (m_request.type == RequestType::long_term_request) {
+ if (m_request.reqType == RequestType::long_term_request) {
// long-term request: Have "message" field from response JSON directly as a reply to the user
response = json.get("message");
if (json.get("status") != "true" ) {
- if (json.get("message") == "License fully reserved") {
+ if (response == "License fully reserved") {
response = replyString[e_license_pool_full];
+ } else if (response.find("cannot be early released") != std::string::npos) {
+ response = replyString[e_no_permanent_to_release];
} else {
response = replyString[e_license_rejected];
}
// Do not touch the license file, just return
return 1;
}
- } else if (m_request.type == RequestType::server_version) {
- std::cout << "Parsing server version response\n";
+ } else if (m_request.reqType == RequestType::server_version) {
response = "Qt License Server v";
response += json.get("version");
return 0; // Do not touch cached license files pls.
diff --git a/src/daemon_clients/cocohandler.h b/src/daemon_clients/cocohandler.h
index d25b36c..d4a32d9 100644
--- a/src/daemon_clients/cocohandler.h
+++ b/src/daemon_clients/cocohandler.h
@@ -13,13 +13,14 @@ class CocoHandler : public ClientHandler {
: ClientHandler(request, settings)
{
m_updateInterval = utils::strToInt(m_settings.get("coco_report_interval"));
+ m_floatingLicense = true;
}
bool isLicenseRequestDue() override { return true; }
bool isCachedReservationValid(std::string &reply) override {return true;}
int parseAndSaveResponse(std::string &response) override { return 0; }
void buildRequestJson() override {return;}
- void release() override
+ void prepareRelease() override
{
// TODO
return;
diff --git a/src/daemon_clients/squishhandler.h b/src/daemon_clients/squishhandler.h
index 366c624..24c5aed 100644
--- a/src/daemon_clients/squishhandler.h
+++ b/src/daemon_clients/squishhandler.h
@@ -15,26 +15,32 @@ class SquishHandler : public ClientHandler {
m_updateInterval = utils::strToInt(m_settings.get("squish_report_interval"));
m_request.operation = OP_ADD_RESERVATION;
m_request.startTimestamp = utils::getTimestampNow();
+ m_license.last_timestamp = 0;
+ m_floatingLicense = true;
}
- bool isLicenseRequestDue() override { return true; }
- bool isCachedReservationValid(std::string &reply) override { return true; }
+ bool isCachedReservationValid(std::string &reply) override { return false; }
void buildRequestJson() override
{
std::stringstream pay;
pay << "{";
- pay<< "\"license_number\":" << "\"" << m_request.licenseId << "\",";
- pay << "\"user_id\":" << "\"" << m_request.userId << "\",";
- pay << "\"hw_id\":" << "\"" << m_settings.get("hw_id") << "\",";
- pay << "\"operation\":" << "\"" << m_request.operation << "\",";
- pay << "\"src\":" << "\"" << m_request.appName << "\",";
- pay << "\"host_os\":" << "\"" << m_settings.get("host_os") << "\",";
- pay << "\"src_version\":" << "\"" << m_request.appVersion << "\",";
- pay << "\"email\":" << "\"" << m_request.email << "\"";
+ pay << "\"license_number\":\"" << m_request.licenseId << "\",";
+ pay << "\"user_id\":\"" << m_request.userId << "\",";
+ pay << "\"hw_id\":\"" << m_settings.get("hw_id") << "\",";
+ pay << "\"operation\":\"" << m_request.operation << "\",";
+ pay << "\"type\":\"" << m_request.runnerType << "\",";
+ pay << "\"src\":\"" << m_request.appName << "\",";
+ pay << "\"host_os\":\"" << m_settings.get("host_os") << "\",";
+ pay << "\"src_version\":\"" << m_request.appVersion << "\",";
+ pay << "\"reservation_id\":\"" << m_request.parentReservationId << "\",";
+ pay << "\"email\":\"" << m_request.email << "\"";
+ if (m_request.operation == OP_QA_RELEASE_RESERVATION) {
+ pay << "\"custom_duration\":\"" << m_request.stopTimestamp
+ - m_request.startTimestamp << "\",";
+ }
pay << "}";
m_request.payload = pay.str();
- m_floatingLicense = true;
}
int parseAndSaveResponse(std::string &response) override
@@ -43,8 +49,6 @@ class SquishHandler : public ClientHandler {
// response JSON is converted to a reply string to the client from now on
std::stringstream ss;
m_license.status = (json.get("status") == "true") ? true : false;
-
-
if (m_license.status) {
ss << replyString[e_license_granted];
ss << " expiry_date=" << json.get("expiry_date");
@@ -65,15 +69,11 @@ class SquishHandler : public ClientHandler {
m_license.user_id = json.get("user_id");
m_license.reservation_id = json.get("reservation_id");
m_license.license_key = json.get("license_key");
- m_license.parent_reservation_id = json.get("parent_reservvation_id");
- m_license.operation = "add";
// Add timestamp into license JSON
- struct timeval tp;
- gettimeofday(&tp, NULL);
- uint64_t timeNow = tp.tv_sec;
+ m_license.last_timestamp = utils::getTimestampNow();
// Save the JSON, adding timestamp
- json.add("last_timestamp", timeNow);
+ json.add("last_timestamp", m_license.last_timestamp);
int result = utils::writeToFile(m_request.licenseFile, json.dump(4));
if (result != 0) {
std::cout << "ERROR saving license file: '" << m_request.licenseFile << "': " << strerror(result) << std::endl;
@@ -81,10 +81,23 @@ class SquishHandler : public ClientHandler {
return 0;
}
- void release() override
+ void prepareRelease() override
{
- m_request.operation = OP_REMOVE_RESERVATION;
+ m_request.operation = OP_QA_RELEASE_RESERVATION;
m_request.stopTimestamp = utils::getTimestampNow();
buildRequestJson();
}
+
+ void resetTimer() override
+ {
+ m_license.last_timestamp = utils::getTimestampNow();
+ }
+
+ bool isLicenseRequestDue() override {
+ uint64_t now = utils::getTimestampNow();
+ if (m_license.last_timestamp == 0) return true; // startup
+ if ((now - m_license.last_timestamp) > m_updateInterval)
+ return true;
+ return false;
+ }
}; \ No newline at end of file
diff --git a/src/daemon_clients/squishidehandler.h b/src/daemon_clients/squishidehandler.h
index a17b2db..8f08e0c 100644
--- a/src/daemon_clients/squishidehandler.h
+++ b/src/daemon_clients/squishidehandler.h
@@ -14,13 +14,14 @@ class SquishIdeHandler : public ClientHandler {
{
m_updateInterval = utils::strToInt(m_settings.get("squish_report_interval"));
m_request.operation = OP_ADD_RESERVATION;
+ m_floatingLicense = true;
}
bool isLicenseRequestDue() override { return true; }
bool isCachedReservationValid(std::string &reply) override {return true;}
void buildRequestJson() override {return;}
int parseAndSaveResponse(std::string &response) override { return 0; }
- void release() override
+ void prepareRelease() override
{
// TODO
return;
diff --git a/src/httpclient.cpp b/src/httpclient.cpp
index 730b310..0682be8 100644
--- a/src/httpclient.cpp
+++ b/src/httpclient.cpp
@@ -7,18 +7,18 @@
size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
{
- std::cout << "Reading data\n";
+ //std::cout << "Reading data\n";
((std::string *)userp)->append(contents, size * nmemb);
return size * nmemb;
}
HttpClient::HttpClient( const std::string &serverUrl,
const std::string &requestAccessPoint,
- const std::string &longtermAccessPoint,
+ const std::string &permanentAccessPoint,
const std::string &versionAccessPoint) :
m_serverUrl(serverUrl),
m_requestAccessPoint(requestAccessPoint),
- m_longtermAccessPoint(longtermAccessPoint),
+ m_permanentAccessPoint(permanentAccessPoint),
m_versionAccessPoint(versionAccessPoint)
{
m_userAgent += DAEMON_VERSION;
@@ -32,6 +32,8 @@ int HttpClient::sendRequest(std::string &reply, const std::string &payload,
/* specify URL to POST */
request.url = server;
+ request.payload = payload;
+
if (server.empty()) {
// If server URL is not given as param, we use the default
request.url = m_serverUrl;
@@ -39,30 +41,26 @@ int HttpClient::sendRequest(std::string &reply, const std::string &payload,
if (!authKey.empty()) {
// normal request
request.url += m_requestAccessPoint;
+ std::string auth = "Authorization: " + authKey;
+ //std::cout << "Setting authorization: " << auth << std::endl;
+ request.headers = curl_slist_append(request.headers, auth.c_str());
} else {
if (payload.empty()) {
// version query
request.url += m_versionAccessPoint;
} else {
- // long-term request
- request.url += m_longtermAccessPoint;
+ // permanentrequest
+ request.url += m_permanentAccessPoint;
}
}
- request.authKey = authKey;
- request.payload = payload;
- if (!request.authKey.empty()) {
- // Set authorization only if applicable
- std::string auth = "Authorization: " + request.authKey;
- request.headers = curl_slist_append(request.headers, auth.c_str());
- }
std::string agent = "User-Agent: " + m_userAgent;
request.headers = curl_slist_append(request.headers, agent.c_str());
request.headers = curl_slist_append(request.headers, "Accept: */*");
request.headers = curl_slist_append(request.headers, "Content-Type: application/json");
request.headers = curl_slist_append(request.headers, "charset: utf-8");
- std::cout << "HTTPClient() -- server URL " << request.url << std::endl;
+ //std::cout << "HTTPClient() -- server URL " << request.url << std::endl;
int retVal = 0;
@@ -78,8 +76,8 @@ int HttpClient::sendRequest(std::string &reply, const std::string &payload,
retVal = 1;
}
if (retVal == 0) {
- std::cout << request.reply.length() << " bytes retrieved from license server:\n";
- std::cout << request.reply << std::endl;
+ std::cout << request.reply.length() << " bytes retrieved from license server\n";
+ //std::cout << request.reply << std::endl;
} else {
std::cout << m_lastError << std::endl;
}
@@ -112,6 +110,9 @@ int HttpClient::doRequest(CURL *curl, HttpRequest &request)
else {
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
}
+ if(curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL) != CURLE_OK) {
+ std::cout << "Warning! No SSL support available\n";
+ }
curl_easy_setopt(curl, CURLOPT_TIMEOUT, SERVER_CONN_TIMEOUT);
// get it
diff --git a/src/jsonhandler.cpp b/src/jsonhandler.cpp
index f46fd72..18430c1 100644
--- a/src/jsonhandler.cpp
+++ b/src/jsonhandler.cpp
@@ -76,10 +76,10 @@ std::string JsonHandler::dump(uint8_t indent)
top << "{";
if (indent > 0) {
res << ind << "\"reservation\": {" << std::endl;
- top << std::endl;
} else {
res << "\"reservation\":{";
}
+ top << std::endl;
uint8_t count = 0;
for (auto const &item : m_items) {
diff --git a/src/licenser.cpp b/src/licenser.cpp
index 66c4c2d..0b3cc48 100644
--- a/src/licenser.cpp
+++ b/src/licenser.cpp
@@ -10,7 +10,7 @@ Licenser::Licenser(uint16_t tcpPort)
// Init daemon settings
settings = new LicdSetup(e_set_type_daemon);
- // Check if our setup already has some hw id - generate it if not
+ // Check if our setup already has some hw id - generate one if not
if (settings->get("hw_id").empty()) {
setHwId();
}
@@ -22,7 +22,7 @@ Licenser::Licenser(uint16_t tcpPort)
// Start the HTTP client
m_http = new HttpClient(settings->get("server_addr"),
settings->get("reservation_access_point"),
- settings->get("long-term_access_point"),
+ settings->get("permanent_access_point"),
settings->get("version_query_access_point"));
// Start the TCP/IP server
m_server = new TcpServer(tcpPort);
@@ -37,7 +37,6 @@ Licenser::~Licenser()
std::cout << "Daemon stopped." << std::endl;
}
-
int Licenser::listen()
{
m_infoString = "";
@@ -45,31 +44,32 @@ int Licenser::listen()
std::string input = m_server->listenToClients(socket);
input = utils::trimStr(input);
if (input.empty()) {
+ if (m_floatingClients.size() > 0) {
+ checkReportsDue();
+ }
return 0; //continue;
}
if (input == CLIENT_CLOSED_MSG) {
std::cout << "Client disconnected, socket id " << socket << std::endl;
- // Now to check if the client had a floating license:
- clientDisconnected(socket);
+ removeClient(socket);
return 0;
}
- std::cout << "Got an request: " << input << std::endl;
+
+ std::cout << "Got a request: " << input << std::endl;
std::string reply = ""; // Holds server response first (if got any). After parsing, holds reply to the client
int clientType = parseInputAndCreateCLient(socket, input);
- std::cout << "Client type: " << clientType << std::endl;
if (clientType != (int)ClientType::client_undefined)
{
if (m_currentClient->parseRequest() != e_bad_request) {
RequestType reqType = m_currentClient->getRequestType();
- std::string payload = "";
if (reqType == RequestType::reservation_query) {
reply = checkReservations();
} else if (reqType == RequestType::daemon_version) {
reply = getDaemonVersion();
} else {
- std::cout << "Initiating request to server\n";
+ std::cout << "Initiating a request to the server\n";
if (m_currentClient->isLicenseRequestDue()) {
if (sendServerRequest(reply) == e_bad_connection) {
// Bad server connection: Check the existing license file for expiry date
@@ -92,7 +92,8 @@ int Licenser::listen()
}
if (m_currentClient->hasFloatingLicense()) {
- // QA tool, Coco or Squish (cLient with floating license): Store it in cache
+ // QA tool, Coco or Squish (client with floating license): Store it in cache
+ std::cout << "Storing client in cache\n";
m_floatingClients.push_back(m_currentClient);
}
@@ -104,17 +105,23 @@ int Licenser::listen()
if (m_floatingClients.size() > 0) {
checkReportsDue();
}
+ std::cout << "Current clients in cache: " << m_floatingClients.size() << std::endl;
return 0;
}
+
int Licenser::checkReportsDue() {
// Check if there's any floating clients which has periodic reports due
- // TODO!!
ClientHandler *client;
for (int i = 0 ; i < m_floatingClients.size(); i++) {
client = m_floatingClients[i];
if (client->isLicenseRequestDue()) {
- // TODO Ping server (Req Json might need updating here)
+ std::string reply;
+ //std::cout << "Reporting to server (socket ID " << client->getSocketId() << std::endl;
+ if (sendServerRequest(reply) != e_bad_connection) {
+ std::cout << "Reported alive floating reservation with socket ID " << client->getSocketId() << std::endl;
+ client->resetTimer();
+ }
}
}
return 0;
@@ -127,6 +134,7 @@ int Licenser::parseInputAndCreateCLient(uint16_t socketId, const std::string &in
// to initiate into m_currentClient member
RequestInfo request;
request.socketId = socketId;
+
// Find out which class of client is calling
ClientType retVal = ClientType::client_undefined;
std::vector<std::string> paramList = utils::splitStr(incoming, '-');
@@ -180,14 +188,20 @@ int Licenser::parseInputAndCreateCLient(uint16_t socketId, const std::string &in
int Licenser::sendServerRequest(std::string &reply)
{
- std::string authKey;
+ std::string auth;
RequestInfo request = m_currentClient->getRequest();
if (request.client != ClientType::client_CLI) {
// Generate auth hash for HTTP headers (CLI tool does not need it)
- doHmacHashSha256(request.payload, settings->get("server_secret"), authKey); // 19755982232ff7b6f6d0f3c57ffc1c0e4f03060e7175d478f7b146fb1e000507";
+ std::string hash;
+ doHmacHashSha256(request.payload, settings->get("server_secret"), hash); // 19755982232ff7b6f6d0f3c57ffc1c0e4f03060e7175d478f7b146fb1e000507";
+ // Bearer is the same hash (?)
+ auth = "apikey " + hash;
+ //auth += ", Bearer " + hash;
}
+
// Send the request
- if (m_http->sendRequest(reply, request.payload, request.serverAddr, authKey) != 0) {
+ std::cout << "Sending request: " << request.payload << std::endl;
+ if (m_http->sendRequest(reply, request.payload, request.serverAddr, auth) != 0) {
return e_bad_connection;
}
return e_got_response;
@@ -196,7 +210,7 @@ int Licenser::sendServerRequest(std::string &reply)
void Licenser::doHmacHashSha256(const std::string &payload, const std::string &secret, std::string &authKey)
{
std::stringstream ss_result;
- ss_result << "apikey ";
+ ss_result << "";
// Allocate memory for the HMAC
std::vector<uint8_t> out(SHA256_HASH_SIZE);
@@ -213,10 +227,6 @@ void Licenser::doHmacHashSha256(const std::string &payload, const std::string &s
authKey = ss_result.str();
JsonHandler pay(payload);
- // Print out the result
- std::cout << "Message: " << pay.dump(4) << std::endl;
- std::cout << "Key: " << secret << std::endl;
- std::cout << "HMAC: " << authKey << std::endl;
}
std::string Licenser::checkReservations()
@@ -246,7 +256,8 @@ std::string Licenser::checkReservations()
return reply.str();
}
-void Licenser::clientDisconnected(int socketId) {
+void Licenser::removeClient(int socketId) {
+ // Check if the client had a floating license:
int index = -1;
ClientHandler *client;
for (int i = 0; i < m_floatingClients.size(); i++) {
@@ -257,13 +268,23 @@ void Licenser::clientDisconnected(int socketId) {
break;
}
}
- if (index != -1 && m_currentClient->hasFloatingLicense()) {
- m_currentClient->release(); // not implemented yet
- // m_floatingClients.erase(index); // TODO don't erase yet, server might be down
+ if (index == -1 ) {
+ // non-floating
+ return;
}
+ // Client has a floating license - need to release the reservation now
-}
+ m_currentClient->prepareRelease();
+ std::string reply;
+ if (sendServerRequest(reply) != e_bad_connection) {
+ // if connection succeeds, we can forget about that client
+ std::cout << "Removing floating reservation with socket ID " << m_currentClient->getSocketId() << std::endl;
+ m_floatingClients.erase(m_floatingClients.begin() + index);
+ }
+
+ return;
+}
std::string Licenser::getDaemonVersion()
{
@@ -273,8 +294,23 @@ std::string Licenser::getDaemonVersion()
}
void Licenser::setHwId() {
-
- // TODO calculate hwid hash out of MAC, uname etc...
- // Edit the qtlicd.ini to make it permanent
+ std::cout << "No HW ID found, generating it ... ";
+ std::string hwInfo = utils::getSystemHwInfoString();
+ std::string hash;
+ doHmacHashSha256(hwInfo, settings->get("server_secret"), hash);
+ std::string settingsString;
+ utils::readFile(settingsString, DAEMON_SETTINGS_FILE);
+ std::vector<std::string> lines = utils::splitStr(settingsString, '\n');
+ settingsString = "";
+ std::string wanted = "hw_id=";
+ for (std::string line : lines) {
+ if (line.substr(0, wanted.length()) == wanted) {
+ line = wanted + hash;
+ }
+ line += '\n';
+ settingsString += line;
+ }
+ utils::writeToFile(DAEMON_SETTINGS_FILE, settingsString);
+ settings->set("hw_id", hash);
return;
-} \ No newline at end of file
+}
diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp
index b1205ba..ebbdf63 100644
--- a/src/tcpserver.cpp
+++ b/src/tcpserver.cpp
@@ -34,7 +34,7 @@ TcpServer::TcpServer(uint16_t serverPort)
perror("setsockopt failed");
exit(EXIT_FAILURE);
}
- timeval tv {2, 0}; //t.tv_sec = 2; t.tv_usec = 0;
+ timeval tv {1, 0}; //t.tv_sec = 2; t.tv_usec = 0;
int ret = setsockopt(m_masterSocket, SOL_SOCKET, SO_RCVTIMEO,
(char*)&tv, sizeof(timeval));
if (ret < 0) {
@@ -105,7 +105,7 @@ std::string TcpServer::listenToClients(int &socket)
max_sd = sd;
}
// timeout
- timeval tv{2, 0}; //t.tv_sec = 2; t.tv_usec = 0;
+ timeval tv{1, 0}; //t.tv_sec = 2; t.tv_usec = 0;
// Wait for an activity on one of the sockets.
int activity = select((int)max_sd + 1, &m_readfds, NULL, NULL, &tv);
@@ -125,6 +125,7 @@ std::string TcpServer::listenToClients(int &socket)
// If position is free
if (m_clientSocket[i] == 0) {
m_clientSocket[i] = new_socket;
+ socket = i;
std::cout << "New connection - adding to list of sockets with id " << i << std::endl;
break;
}
@@ -147,6 +148,7 @@ std::string TcpServer::listenToClients(int &socket)
getpeername(sd, (struct sockaddr *)&m_address,
(socklen_t *)&m_addrlen);
// Close the socket and mark as 0 in list for reuse
+ socket = i;
doCloseSocket(sd);
m_clientSocket[i] = 0;
data = "closed";
diff --git a/src/utils.cpp b/src/utils.cpp
index cb68829..1fa48f7 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -158,7 +158,7 @@ int readFile(std::string &str, const std::string &filepath)
if (file.is_open()) {
std::string line;
while (getline(file, line)) {
- ss << line;
+ ss << line << std::endl;
}
file.close();
} else {
@@ -237,13 +237,13 @@ std::vector<std::string> getDirListing(const std::string &directory, const std::
int deleteFile(const std::string &filepath)
{
- std::remove(filepath.c_str()); // delete file
- bool failed = !std::ifstream("file1.txt");
- if(failed) {
- std::perror("Error deleting file");
- return 1;
+ if (fileExists(filepath)) {
+ std::remove(filepath.c_str()); // delete file
+ return 0;
}
- return 0;
+ std::cout << "No file " << filepath << " found to delete\n";
+
+ return 1;
}
std::string getOsName()
@@ -263,6 +263,24 @@ std::string getOsName()
#endif
}
+std::string getSystemHwInfoString() {
+ // Trying to get individual HW string, using network parameters and current time (epoch)
+ std::stringstream hwInfo;
+ std::string ip_mac;
+#if _WIN32
+ system("ipconfig > hw.txt");
+#elif __APPLE__ || __MACH__
+ system("ifconfig > hw.txt");
+#elif __linux__
+ system("ip addr > hw.txt");
+#endif
+ readFile(ip_mac, "hw.txt");
+ hwInfo << getTimestampNow() << std::endl << ip_mac;
+ deleteFile("hw.txt");
+ return hwInfo.str();
+}
+
+
#if _WIN32
/*
* Windows implementation of missing POSIX strptime()