aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Littow <sami@Alten-MacBook.local>2022-12-19 10:31:49 +0200
committerSami <sami.littow@qt.io>2022-12-30 08:14:17 +0200
commitef4ba13bff5d2d0499e8af9f405ecf506aaa85d6 (patch)
tree615c90d95662b09a89790328292019818158bc18
parentac5b2c916e9234947df8c240227b260330f97150 (diff)
Refactoring (prepare for QA tools support)
-rw-r--r--CHANGELOG6
-rw-r--r--CMakeLists.txt18
-rw-r--r--include/commonsetup.h92
-rw-r--r--include/jsonhandler.h1
-rw-r--r--include/licdsetup.h7
-rw-r--r--include/licenser.h71
-rw-r--r--include/tcpserver.h2
-rw-r--r--include/utils.h8
-rw-r--r--licd.ini19
-rw-r--r--licenser.cpp428
-rw-r--r--linux_daemon/linuxdaemon.cpp12
-rw-r--r--mocwrapper/CMakeLists.txt6
-rw-r--r--mocwrapper/mocwrapper.cpp2
-rw-r--r--qtlicensetool/CMakeLists.txt6
-rw-r--r--qtlicensetool/qtlicensetool.cpp18
-rw-r--r--src/clienthandler.cpp120
-rw-r--r--src/daemon_clients/clienthandler.h64
-rw-r--r--src/daemon_clients/clitoolhandler.h74
-rw-r--r--src/daemon_clients/cocohandler.h28
-rw-r--r--src/daemon_clients/mochandler.h105
-rw-r--r--src/daemon_clients/pluginhandler.h77
-rw-r--r--src/daemon_clients/squishhandler.h90
-rw-r--r--src/daemon_clients/squishidehandler.h28
-rw-r--r--src/dummy_licheck.cpp (renamed from dummy_licheck.cpp)0
-rw-r--r--src/httpclient.cpp (renamed from httpclient.cpp)1
-rw-r--r--src/jsonhandler.cpp (renamed from jsonhandler.cpp)0
-rw-r--r--src/licdsetup.cpp (renamed from licdsetup.cpp)0
-rw-r--r--src/licenser.cpp280
-rw-r--r--src/tcpclient.cpp (renamed from tcpclient.cpp)0
-rw-r--r--src/tcpserver.cpp (renamed from tcpserver.cpp)12
-rw-r--r--src/utils.cpp (renamed from utils.cpp)21
31 files changed, 1057 insertions, 539 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 4fec1af..3a43a14 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -33,3 +33,9 @@ Changes in 2.0.3:
Changes in 2.0.4:
- Changed daemon response message in case there is no licenses left in the pool
+
+Changes in 2.1.0:
+- Floating license support added (Squish)
+- Daemon name 'licd' changed to 'qtlicd'
+- Concept of "long-term" changed to "permanent"
+- Daemon architecture changed towards more modular approach
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb71ed5..585a7cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,15 +16,17 @@ ADD_DEFINITIONS(-DUNICODE)
ADD_DEFINITIONS(-D_UNICODE)
list(APPEND targetSrc
- ${CMAKE_CURRENT_LIST_DIR}/licenser.cpp
- ${CMAKE_CURRENT_LIST_DIR}/tcpserver.cpp
- ${CMAKE_CURRENT_LIST_DIR}/httpclient.cpp
- ${CMAKE_CURRENT_LIST_DIR}/jsonhandler.cpp
- ${CMAKE_CURRENT_LIST_DIR}/utils.cpp
- ${CMAKE_CURRENT_LIST_DIR}/licdsetup.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/licenser.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/tcpserver.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/httpclient.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/jsonhandler.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/utils.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/licdsetup.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/clienthandler.cpp
)
list(APPEND includes
${CMAKE_CURRENT_LIST_DIR}/include
+ ${CMAKE_CURRENT_LIST_DIR}/src/daemon_clients
${CMAKE_CURRENT_LIST_DIR}/3rdparty
)
@@ -66,13 +68,11 @@ message("Libs: ${libs}")
add_subdirectory(3rdparty/hmac_sha256)
add_subdirectory(qtlicensetool)
add_subdirectory(mocwrapper)
-add_executable(licheck dummy_licheck.cpp)
+add_executable(licheck src/dummy_licheck.cpp)
add_executable(${PROJECT_NAME} ${targetSrc})
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
target_link_options(${PROJECT_NAME} PRIVATE "/NODEFAULTLIB:LIBCMT")
target_link_options(${PROJECT_NAME} PRIVATE "/NODEFAULTLIB:MSVCRTD")
- #add_executable(svccontrol windowsdaemon/SvcControl.cpp)
- #add_executable(svcconfig windowsdaemon/SvcConfig.cpp)
endif ()
target_include_directories(${PROJECT_NAME} PUBLIC ${includes})
target_link_libraries(${PROJECT_NAME} ${libs} )
diff --git a/include/commonsetup.h b/include/commonsetup.h
index f523216..a3cf72e 100644
--- a/include/commonsetup.h
+++ b/include/commonsetup.h
@@ -2,10 +2,10 @@
*
* SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
*/
-
#pragma once
#include <map>
+#include <string>
#include "version.h"
#define DAEMON_ADDR "localhost"
@@ -16,17 +16,24 @@
#define DEFAULT_USER_SETTINGS_TAG "[default]"
#define SERVER_VERSION_CMD "serverversion"
-#define DAEMON_VERSION_CMD "version"
-#define RESERVATION_QUERY_CMD "reservation"
+#define DAEMON_VERSION_CMD "daemon_version"
+#define RESERVATION_QUERY_CMD "reservation_query"
#define LICENSE_REQUEST_CMD "license"
#define LONGTERM_REQUEST_CMD "longterm"
-#define LONGTERM_ADD_OP "add"
-#define LONGTERM_REMOVE_OP "remove"
+#define OP_ADD_RESERVATION "add"
+#define OP_REMOVE_RESERVATION "remove"
+#define QTLICENSETOOL_APP_NAME "clitool"
+#define SQUISH_IDE_APP_NAME "squish-ide"
+#define SQUISH_APP_NAME "squish"
+#define COCO_APP_NAME "coco"
#define MOCWRAPPER_APP_NAME "moc"
+#define CREATOR_APPNAME "qtcreator"
+#define DESIGN_STUDIO_APP_NAME "qtdesignstudio"
#define ORIGINAL_MOC_PREFIX "orig_"
-#define QTLICENSETOOL_APP_NAME "Qt License Tool"
+#define LICENSE_FILE_PREFIX "lic_"
+#define LICENSE_FILE_EXTENSION ".json"
#if __APPLE__ || __MACH__
#define WORKING_DIR "/opt/licd"
@@ -36,7 +43,76 @@
#define WORKING_DIR "C:/Program Files/licd/"
#endif
#define DAEMON_SETTINGS_FILE WORKING_DIR "/licd.ini"
-#define LICENSE_FILE_BASE WORKING_DIR "/lic_"
#define SHA256_HASH_SIZE 32
#define SECS_IN_HOUR 3600
-#define SECS_IN_DAY (SECS_IN_HOUR * 24)
+#define SECS_IN_DAY 86400
+
+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;
+ bool status = false;
+ std::string expiry_date;
+ std::string operation;
+ std::string license_key;
+ std::string license_id;
+ std::string reservation_id;
+ std::string parent_reservation_id; // TODO Coming with qa tools: Check with server end!
+ std::string user_id;
+};
+
+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
+};
+
+enum class RequestType {
+ no_request = 0,
+ license_request = 1,
+ keepalive_report = 2,
+ license_release = 3,
+ long_term_request = 4,
+ server_version = 5,
+ daemon_version = 6,
+ reservation_query = 7,
+};
+
+enum class ClientType {
+ client_undefined = -1,
+ client_moc = 1,
+ client_plugin,
+ client_CLI,
+ client_squish,
+ client_squish_ide,
+ client_coco
+};
+
+// Struct to store request info
+struct RequestInfo {
+ uint16_t socketId;
+ RequestType type = RequestType::no_request;
+ ClientType client;
+ uint16_t updateIntervalSecs;
+ std::string licenseFile;
+ std::string reservationID;
+ std::string operation;
+ std::string appName;
+ std::string appVersion;
+ std::string userId;
+ std::string licenseId;
+ std::string email;
+ std::string payload;
+ 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 parentReservationId; // used by QA-Tools only
+};
+
diff --git a/include/jsonhandler.h b/include/jsonhandler.h
index 1f334cd..18baad0 100644
--- a/include/jsonhandler.h
+++ b/include/jsonhandler.h
@@ -2,7 +2,6 @@
*
* SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
*/
-
#pragma once
#include <algorithm>
diff --git a/include/licdsetup.h b/include/licdsetup.h
index ec2ed71..41c5564 100644
--- a/include/licdsetup.h
+++ b/include/licdsetup.h
@@ -2,6 +2,8 @@
*
* SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
*/
+#pragma once
+
#include "commonsetup.h"
#include "utils.h"
@@ -22,7 +24,10 @@ enum settings_owner_type {
e_set_type_daemon = 0,
e_set_type_moc = 1,
e_set_type_licensetool = 2,
- e_set_type_other = 3
+ e_set_type_squish = 3,
+ e_set_type_squish_ide = 4,
+ e_aet_type_coco = 5,
+ e_set_type_other
};
class LicdSetup
diff --git a/include/licenser.h b/include/licenser.h
index 00ba815..449ee9a 100644
--- a/include/licenser.h
+++ b/include/licenser.h
@@ -13,91 +13,56 @@
#include <ctime>
#include <cassert>
#if _WIN32
- #define WIN32_LEAN_AND_MEAN
// Windows
+ #define WIN32_LEAN_AND_MEAN
//#include <windows.h>
#else
#endif
-#include "commonsetup.h"
#include "httpclient.h"
#include "tcpserver.h"
#include "utils.h"
#include "hmac_sha256.h"
#include "jsonhandler.h"
#include "licdsetup.h"
-
-enum RequestReply {
- e_bad_request = -1,
- e_license_granted = 0,
- e_license_rejected = 1,
- e_no_conn_leeway = 2,
- e_license_pool_full = 3,
- e_bad_connection = 4
-};
-
-enum class RequestType {
- no_request = 0,
- normal_license_renewal = 1,
- long_term_request = 2,
- server_version = 3,
- daemon_version = 4,
- reservation_query = 5
-};
-
-// Struct to store incoming request info for easier handling
-struct RequestInfo {
- RequestType type = RequestType::no_request;
- std::string operation;
- std::string appName;
- std::string appVersion;
- std::string userId;
- std::string licenseId;
- std::string email;
- std::string licenseFile;
- std::string userHome;
- std::string payload;
- std::string serverAddr;
-};
+#include "clienthandler.h"
+#include "mochandler.h"
+#include "clitoolhandler.h"
+#include "pluginhandler.h"
+#include "cocohandler.h"
+#include "squishhandler.h"
+#include "squishidehandler.h"
class Licenser
{
public:
explicit Licenser(uint16_t tcpPort = 0);
~Licenser();
+
int listen();
- int sendLicensingRequest(std::string &reply, const RequestInfo &request);
- int sendLongTermRequest(std::string &reply, const RequestInfo &request);
- int getListeningPort();
+ int sendServerRequest(std::string &reply);
private:
HttpClient *m_http;
TcpServer *m_server;
uint64_t m_mocInterval;
std::string m_infoString;
+ ClientHandler *m_currentClient;
+ std::vector<ClientHandler*> m_floatingClients;
- int parseIncoming(const std::string &incoming, RequestInfo &request);
- int buildRequestJson(RequestInfo &request);
- int parseAndSaveJsonReply(std::string &reply, const RequestInfo &request);
- bool checkLicenseExpiryDate(std::string &reply, const RequestInfo &request);
- bool isMocRenewalDue(const std::string &licenseFile);
+ int parseInputAndCreateCLient(uint16_t socketId, const std::string &incoming);
void doHmacHashSha256(const std::string &payload, const std::string &secret, std::string &authKey);
int initDaemonSettings();
std::string checkReservations();
std::string askServerVersion();
- std::string getVersion();
+ std::string getDaemonVersion();
+ int checkReportsDue();
+ void clientDisconnected(int socketId);
+ void setHwId();
LicdSetup *settings;
-
- std::map<RequestReply, std::string> replyString {
- {e_bad_request, "ERROR Bad request"},
- {e_license_granted, "License acquired."},
- {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_bad_connection, "No connection to server. Try again later."}
- };
};
+
#ifndef __TIME_IMP
#define __TIME_IMP
#if _WIN32
diff --git a/include/tcpserver.h b/include/tcpserver.h
index 57f7930..f7def7a 100644
--- a/include/tcpserver.h
+++ b/include/tcpserver.h
@@ -15,6 +15,8 @@
#define TRUE 1
#define FALSE 0
+#define CLIENT_CLOSED_MSG "closed"
+
#if __APPLE__ || __MACH__ || __linux__
#include <sys/types.h>
#include <sys/socket.h>
diff --git a/include/utils.h b/include/utils.h
index b8eceb0..13a4e6c 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -3,9 +3,11 @@
* SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
*/
#pragma once
+#include "commonsetup.h"
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/time.h>
#include <iostream>
#include <fstream>
#include <sstream>
@@ -13,6 +15,8 @@
#include <algorithm>
#include <ctime>
#include <cstring>
+
+
#if _WIN32
// Windows
#define WIN32_LEAN_AND_MEAN
@@ -61,13 +65,15 @@ bool fileExists(const std::string &name);
std::string getFileOwnerName(const std::string &filename);
int getFileOwner(const std::string &filename, uint16_t &owner, uint16_t &group);
std::vector<std::string> getDirListing(const std::string &directory, const std::string &filter = "");
+int deleteFile(const std::string &filepath);
/*
* Other
*/
-// Time conversions
+// Time utils
std::string epochToString(time_t epochTime, const char* format = "%Y-%m-%d %H:%M:%S");
time_t stringToEpoch(const char* theTime, const char* format = "%Y-%m-%d %H:%M:%S");
+uint64_t getTimestampNow();
// Find out host OS
std::string getOsName();
diff --git a/licd.ini b/licd.ini
index e619c4b..c9ee56f 100644
--- a/licd.ini
+++ b/licd.ini
@@ -33,20 +33,21 @@ long-term_access_point=/api/v2/reservations/long-term
# Type: string
version_query_access_point=/api/v2/ping
###################
-# moc_request_interval
+# moc_renewal_interval
# Duration (in hours) after which MOC license requests will be renewed (request forwarded to the server).
# In the meantime, timestamp stored in the license file will be used
# Type: int
moc_renewal_interval=24
###################
-# license_file
-# filename for storing license server reply JSON. Note! Username and license ID will be added to this
-# Type: string
-license_file_base=lic_
-# license_file_extension
-# filename extension for storing license server reply JSON
-# Type: string
-license_file_extension=.json
+# squish_report_interval
+# Duration (in secs) between update calls to the server while Squish is working.
+# Type: int
+squish_report_interval=300
+###################
+# coco_update_interval
+# Duration (in secs) between update calls to the server while Coco is working.
+# Type: int
+coco_update_interval=5
###################
# TCP/IP port where the daemon is listening for requests
tcp_listening_port=60000
diff --git a/licenser.cpp b/licenser.cpp
deleted file mode 100644
index ca52e4b..0000000
--- a/licenser.cpp
+++ /dev/null
@@ -1,428 +0,0 @@
-/* Copyright (C) 2022 The Qt Company Ltd.
- *
- * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
-*/
-
-#include "licenser.h"
-
-Licenser::Licenser(uint16_t tcpPort)
-{
- // Init daemon settings
- settings = new LicdSetup(e_set_type_daemon);
-
- if (tcpPort == 0) {
- tcpPort = utils::strToInt(settings->get("tcp_listening_port"));
- }
- m_mocInterval = utils::strToInt(settings->get("moc_renewal_interval")) * 3600; // 3600 = secs in hour
- // 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("version_query_access_point"));
- // Start the TCP/IP m_server
- m_server = new TcpServer(tcpPort);
-
-
-}
-
-Licenser::~Licenser()
-{
- delete(settings);
- delete(m_server);
- delete(m_http);
- std::cout << "Daemon stopped." << std::endl;
-}
-
-int Licenser::listen()
-{
-
- m_infoString = "";
- int socket = 0; // Placeholder for whatever socket gets active
- std::string input = m_server->listenToClients(socket);
- input = utils::trimStr(input);
- if (input.empty()) {
- return 0; //continue;
- }
- std::cout << "Got an request: " << input << std::endl;
- RequestInfo request;
- std::string reply = "";
- if (parseIncoming(input, request) == 0) {
- std::string payload = "";
- if (request.type == RequestType::normal_license_renewal) {
- std::cout << "Standard license renewal request\n";
- // See if it's MOC who's calling. Make sure app name is accepted, no matter of the case.
- // request.appname is set in lowercase already in parseIncoming() method at this point
- if (request.appName == utils::strToLower(MOCWRAPPER_APP_NAME)) {
- // More than 24hrs (licd.ini default) from last successful request?
- if (!isMocRenewalDue(request.licenseFile)) {
- // No - Just send ok message and no further actions needed
- reply = replyString[e_license_granted];
- m_server->sendResponse(socket, reply);
- return 0; //continue;
- }
- }
- if (buildRequestJson(request) == 0) {
- if (sendLicensingRequest(reply, request) != 0) {
- // Bad server connection: Check the existing license file for expiry date
- checkLicenseExpiryDate(reply, request);
- } else {
- parseAndSaveJsonReply(reply, request);
- }
- } else {
- reply = replyString[e_bad_request];
- }
- } else if (request.type == RequestType::long_term_request) {
- std::cout << "Long-term license request\n";
- if (buildRequestJson(request) == 0) {
- if (sendLongTermRequest(reply, request) != 0) {
- reply = replyString[e_bad_connection];
- reply += m_http->error();
- } else {
- parseAndSaveJsonReply(reply, request);
- }
- }
- } else if (request.type == RequestType::reservation_query) {
- reply = checkReservations();
- } else if (request.type == RequestType::server_version) {
- reply = askServerVersion();
- }
- else if (request.type == RequestType::daemon_version) {
- reply = getVersion();
- }
- } else {
- reply = replyString[e_bad_request] + '\n';
- }
- reply += m_infoString;
- reply +="\n";
- m_server->sendResponse(socket, reply);
- std::cout << "Replied to socket " << socket << ": " << reply << std::endl;
- return 0;
-}
-
-std::string Licenser::getVersion()
-{
- std::string version = "Qt License Daemon (licd) v";
- version += DAEMON_VERSION;
- return version;
-}
-
-int Licenser::parseIncoming(const std::string &incoming, RequestInfo &request)
-{
- std::vector<std::string> req = utils::splitStr(incoming, '-');
-
- // First find out the command (and operation for longterm case)
- std::string cmd = utils::trimStr(req[0]);
- if (cmd == LICENSE_REQUEST_CMD) {
- request.type = RequestType::normal_license_renewal;
- } else if (cmd.substr(0, 8) == LONGTERM_REQUEST_CMD) {
- request.type = RequestType::long_term_request;
- std::string op = utils::trimStr(cmd.substr(8, cmd.length() -1));
- if (op != LONGTERM_ADD_OP && op != LONGTERM_REMOVE_OP) {
- m_infoString = "Invalid longterm operation: " + op;
- std::cout << m_infoString;
- return e_bad_request;
- }
- request.operation = op;
- } else if (cmd == SERVER_VERSION_CMD) {
- request.type = RequestType::server_version;
- } else if (cmd == DAEMON_VERSION_CMD) {
- request.type = RequestType::daemon_version;
- return 0;
- } else if (cmd == RESERVATION_QUERY_CMD) {
- request.type = RequestType::reservation_query;
- return 0;
- } else {
- std::cout << "Invalid command: " << cmd << std::endl;
- return e_bad_request;
- }
-
- // Then cycle through parameters. Start from [1] because [0] is the command
- for (int i = 1; i < req.size(); i++) {
- std::string item = req[i];
- char arg = (char)item[0];
- std::string val = utils::trimStr(item.substr(1, item.length() - 1));
- if (val.length() == 0) {
- m_infoString = "No value for argument: -";
- m_infoString.push_back(arg);
- std::cout << m_infoString << std::endl;
- return e_bad_request;
- }
-
- if (arg == 'a') request.appName = utils::strToLower(val);
- else if (arg == 'v') request.appVersion = val;
- else if (arg == 'u') request.userId = val;
- else if (arg == 'i') request.licenseId = val;
- else if (arg == 'l') request.serverAddr = val;
- else {
- m_infoString = "Invalid argument: -";
- m_infoString.push_back(arg);
- return e_bad_request;
- }
- }
-
- // Sanity checks. May not be needed after all, if the clients are made correctly.
- if (request.type == RequestType::server_version) {
- return 0; // version query has no mandatory parameters, no checks
- }
-
- bool fail = false;
- if (request.userId.empty()) {
- std::cout << "Missing argument: Username (-u)\n";
- fail = true;
- }
- if (request.licenseId.empty()) {
- std::cout << "Missing argument: License ID (-i)\n";
- fail = true;
- }
- if (request.type == RequestType::normal_license_renewal) {
- if (request.appName.empty()) {
- std::cout << "Missing argument: Application name (-a)\n";
- fail = true;
- }
- if (request.appVersion.empty()) {
- std::cout << "Missing argument: Application version (-v)\n";
- fail = true;
- }
- } else if (request.type == RequestType::long_term_request) {
- if (request.operation.empty()) {
- m_infoString = "Missing argument: Longterm operation (add/remove)\n";
- std::cout << m_infoString << std::endl; // For logging
- fail = true;
- }
- }
- if (fail) {
- return e_bad_request;
- }
-
- // Add user info to the license filename
- std::stringstream ss;
- ss << WORKING_DIR << DIR_SEPARATOR
- << settings->get("license_file_base") << request.userId
- << "_" << request.licenseId << settings->get("license_file_extension");
- request.licenseFile = ss.str();
-
- return 0;
-}
-
-int Licenser::buildRequestJson(RequestInfo &request)
-{
- std::stringstream pay;
- pay << "{";
- pay<< "\"license_number\":" << "\"" << request.licenseId << "\",";
- pay << "\"user_id\":" << "\"" << request.userId << "\",";
- if (request.type == RequestType::normal_license_renewal) {
- pay << "\"hw_id\":" << "\"" << settings->get("hw_id") << "\",";
- pay << "\"src\":" << "\"" << request.appName << "\",";
- pay << "\"host_os\":" << "\"" << settings->get("host_os") << "\",";
- pay << "\"src_version\":" << "\"" << request.appVersion << "\",";
- pay << "\"email\":" << "\"" << request.email << "\"";
- } else if (request.type == RequestType::long_term_request) {
- pay << "\"operation\":" << "\"" << request.operation << "\"";
- }
- pay << "}";
- request.payload = pay.str();
- return 0;
-}
-
-int Licenser::parseAndSaveJsonReply(std::string &reply, const RequestInfo &request)
-{
- JsonHandler json(reply);
- std::stringstream ss;
- if (request.type == RequestType::long_term_request) {
- // long-term request: Have "message" from response JSON directly as a reply to the user
- reply = json.get("message");
- if (json.get("status") != "true" ) {
- return 1;
- }
- // Nothing to add to the server message
- } else {
- if (json.get("status") == "true") {
- ss << replyString[e_license_granted];
- ss << " expiry_date=" << json.get("expiry_date");
- ss << " license_id=" << json.get("license_number");
- ss << " reservation_id=" << json.get("reservation_id");
- reply = ss.str();
- } else {
- if (json.get("message") == "License fully reserved") {
- reply = replyString[e_license_pool_full];
- } else {
- reply = replyString[e_license_rejected];
- }
- // Do not save the response json, just return
- return 1;
- }
- }
-
- // Add timestamp into license JSON
- struct timeval tp;
- gettimeofday(&tp, NULL);
- uint64_t timeNow = tp.tv_sec;
-
- // Save the JSON, adding timestamp
- json.add("last_timestamp", timeNow);
- int result = utils::writeToFile(request.licenseFile, json.dump(4));
- if (result != 0) {
- std::cout << "ERROR saving license file: '" << request.licenseFile << "': " << strerror(result) << std::endl;
- }
- return 0;
-}
-
-bool Licenser::checkLicenseExpiryDate(std::string &reply, const RequestInfo &request)
-{
- std::cout << "Offline - checking validity from license file " << request.licenseFile << std::endl;
- // Open the license file
- std::string data;
- if (utils::readFile(data, request.licenseFile) != 0) {
- std::cout << "No license file - rejecting license " << request.licenseFile << std::endl;
- reply = replyString[e_bad_connection];
- return false;
- }
- JsonHandler license(data);
- // Check license status
- if (license.get("status") != "true") {
- std::cout << "License status = false: Rejecting license\n";
- reply = replyString[e_bad_connection];
- return false;
- }
- // Expiry date. Add 1 day to expiry date to get the end actually at the beginning of the next day
- std::string expDate = license.get("expiry_date");
- std::time_t expEpoch = utils::stringToEpoch(expDate.c_str()) + SECS_IN_DAY;
- // Current date
- std::time_t current = std::time(0);
- // See if the time has expire
- if (current > expEpoch) {
- std::cout << "Expiry date " << expDate << " exceeded" << std::endl;
- // License expired: Allow some leeway time for MOC and Plugin, but not for qtlicensetool
- if (utils::strToLower(request.appName) != utils::strToLower(QTLICENSETOOL_APP_NAME)) {
- int leewayTimeLeft = expEpoch + (license.getInt("leeway_hours") * SECS_IN_HOUR) - current;
- if (leewayTimeLeft > 0) {
- std::stringstream ss;
- ss << replyString[RequestReply::e_no_conn_leeway]
- << std::fixed << std::setprecision(1)
- << (float)leewayTimeLeft / SECS_IN_DAY << " days";
- reply = ss.str();
- return true;
- } else {
- std::cout << "No leeway time left" << std::endl;
- }
- }
- std::cout << "Rejecting license\n";
- reply = replyString[e_license_rejected];
- return false;
- }
- std::cout << "License granted, expires at " << expDate << std::endl;
- reply = replyString[e_license_granted];
- return true;
-}
-
-bool Licenser::isMocRenewalDue(const std::string &licenseFile)
-{
- std::cout << "MOC calling, checking if renewal is needed\n";
- // Open the license file
- std::string data;
- if (utils::readFile(data, licenseFile) != 0) {
- // If there is no license file yet, have to request anyway
- std::cout << "No license file present (" << licenseFile << ") - requesting license\n";
- return true;
- }
- JsonHandler license(data);
- if (license.get("status") != "true") {
- // Failed license file shouldn't exist - just to be sure:
- return true;
- }
- // Get current time
- struct timeval tp;
- gettimeofday(&tp, NULL);
- uint64_t timeNow = tp.tv_sec;
- if (timeNow > utils::strToInt(license.get("last_timestamp")) + m_mocInterval) {
- // Renewal is due
- std::cout << "Requesting license renewal\n";
- return true;
- }
- std::cout << "Renewal time not due, granting license\n";
-
- return false;
-}
-
-int Licenser::sendLicensingRequest(std::string &reply, const RequestInfo &request)
-{
- // Generate auth hash
- std::string authKey;
- doHmacHashSha256(request.payload, settings->get("server_secret"), authKey); // 19755982232ff7b6f6d0f3c57ffc1c0e4f03060e7175d478f7b146fb1e000507";
-
- // Send the request
- if (m_http->sendRequest(reply, request.payload, request.serverAddr, authKey) != 0) {
- return -1;
- }
- return 0;
-}
-
-int Licenser::sendLongTermRequest(std::string &reply, const RequestInfo &request)
-{
- if (m_http->sendRequest(reply, request.payload, request.serverAddr) != 0) {
- return -1;
- }
- return 0;
-}
-
-void Licenser::doHmacHashSha256(const std::string &payload, const std::string &secret, std::string &authKey)
-{
- std::stringstream ss_result;
- ss_result << "apikey ";
-
- // Allocate memory for the HMAC
- std::vector<uint8_t> out(SHA256_HASH_SIZE);
-
- // Call hmac-sha256 function
- hmac_sha256(secret.data(), secret.size(), payload.data(), payload.size(),
- out.data(), out.size());
-
- // Convert `out` to string with std::hex
- for (uint8_t x : out) {
- ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)x;
- }
-
- 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()
-{
- // Open all license files
- std::string dir = WORKING_DIR;
- std::string filter = settings->get("license_file_base");
- std::vector<std::string> files = utils::getDirListing(dir, filter);
- std::stringstream reply;
- reply << "Current reservations: \n";
- for (auto file : files) {
- std::string data;
- if (utils::readFile(data, file) != 0) {
- std::cout << "Couldn't read license file: " << file << std::endl;
- continue;
- }
- JsonHandler json(data);
- reply << "\n--- License ID " << json.get("license_number") << " ---\n";
- reply << " User ID: " << json.get("user_id") << std::endl;
- reply << " Expiry date: " << json.get("expiry_date") << std::endl;
- reply << " Reservation ID: " << json.get("reservation_id") << std::endl;
- }
- return reply.str();
-}
-
-std::string Licenser::askServerVersion()
-{
- std::string reply;
- if (m_http->sendRequest(reply, "", "") != 0) {
- reply = replyString[e_bad_connection];
- } else if (reply.find("Error") == std::string::npos) {
- JsonHandler json(reply);
- reply = "Qt License Server v";
- reply += json.get("version");
- }
- return reply;
-}
diff --git a/linux_daemon/linuxdaemon.cpp b/linux_daemon/linuxdaemon.cpp
index 3f9e565..55b883d 100644
--- a/linux_daemon/linuxdaemon.cpp
+++ b/linux_daemon/linuxdaemon.cpp
@@ -5,6 +5,7 @@
#include <sys/stat.h>
#include <iostream>
#include <unistd.h>
+
#include "licenser.h"
#include "version.h"
@@ -23,7 +24,6 @@ int startProcess(uint16_t tcpPort) {
return -1;
}
}
-
}
int main(int argc, char *argv[])
@@ -41,15 +41,15 @@ int main(int argc, char *argv[])
return res;
}
// If command-line parameter is "--version", show the version and exit.
- if (strcmp(argv[1], "--version") == 0) {
+ else if (strcmp(argv[1], "--version") == 0) {
std::cout << "Qt License Daemon (licd) v" << DAEMON_VERSION << " "
<< COPYRIGHT_TEXT << std::endl;
return 0;
}
- if (strcmp(argv[i], "--port") == 0) {
+ else if (strcmp(argv[i], "--port") == 0) {
if (i + 1 == argc) {
all_ok = false;
- printf("No port number given");
+ printf("No port number given\n");
break;
}
try {
@@ -67,7 +67,7 @@ int main(int argc, char *argv[])
break;
}
else {
- printf("Invalid argument: %s", argv[i]);
+ printf("Invalid argument: %s\n", argv[i]);
all_ok = false;
break;
}
@@ -76,6 +76,8 @@ int main(int argc, char *argv[])
printf("\nUsage: qtlicenser [option] [value]\n");
printf("Supported options are:\n");
printf(" --port <port number> : Specify TCP/IP server port. If omitted, default is used.\n");
+ printf(" --nodaemon : Run in non-daemon mode (in console like any other CLI app)\n");
+ printf(" --version : Version info\n");
printf(" --help : This help\n\n");
return -1;
}
diff --git a/mocwrapper/CMakeLists.txt b/mocwrapper/CMakeLists.txt
index 5ce10e8..0189642 100644
--- a/mocwrapper/CMakeLists.txt
+++ b/mocwrapper/CMakeLists.txt
@@ -19,7 +19,7 @@ include_directories (
add_executable(mocwrapper
mocwrapper.cpp
- ../tcpclient.cpp
- ../utils.cpp
- ../licdsetup.cpp
+ ../src/tcpclient.cpp
+ ../src/utils.cpp
+ ../src/licdsetup.cpp
)
diff --git a/mocwrapper/mocwrapper.cpp b/mocwrapper/mocwrapper.cpp
index f4ca9ef..d22137c 100644
--- a/mocwrapper/mocwrapper.cpp
+++ b/mocwrapper/mocwrapper.cpp
@@ -64,7 +64,7 @@ int requestLicense(const std::string &mocBinPath)
std::string addr = user.get("licd_addr");
uint16_t port = utils::strToInt(user.get("licd_port"));
std::stringstream ss;
- ss << "license -u " << user.get("user_id") << " -i " << user.get("license_id")
+ ss << "license -u " << user.get("user_id") << "-e " << user.get("user_email") << " -i " << user.get("license_id")
<< " -a " << MOCWRAPPER_APP_NAME << " -v " << MOCWRAPPER_VERSION;
if (user.get("license_server_addr").length() > 0) {
ss << " -l " << user.get("license_server_addr") << ":" << user.get("license_server_port");
diff --git a/qtlicensetool/CMakeLists.txt b/qtlicensetool/CMakeLists.txt
index 8e9fefd..c2f5c21 100644
--- a/qtlicensetool/CMakeLists.txt
+++ b/qtlicensetool/CMakeLists.txt
@@ -24,7 +24,7 @@ include_directories (
add_executable(qtlicensetool
qtlicensetool.cpp
- ../tcpclient.cpp
- ../utils.cpp
- ../licdsetup.cpp
+ ../src/tcpclient.cpp
+ ../src/utils.cpp
+ ../src/licdsetup.cpp
)
diff --git a/qtlicensetool/qtlicensetool.cpp b/qtlicensetool/qtlicensetool.cpp
index 66f07bd..75f0343 100644
--- a/qtlicensetool/qtlicensetool.cpp
+++ b/qtlicensetool/qtlicensetool.cpp
@@ -49,6 +49,10 @@ void showVersion()
int askStatus(const std::string &statusRequest, LicdSetup *setup)
{
+ std::string req = statusRequest + " -a ";
+ req += QTLICENSETOOL_APP_NAME;
+ req += " -v ";
+ req += QTLICENSETOOL_VERSION;
std::string daemonAddr = setup->get("licd_addr");
int daemonPort = utils::strToInt(setup->get("licd_port"));
if (daemonPort < 0) {
@@ -58,7 +62,7 @@ int askStatus(const std::string &statusRequest, LicdSetup *setup)
// Connect and send/receive the request
TcpClient tcp(daemonAddr, daemonPort);
std::string reply;
- int result = tcp.sendAndReceive(statusRequest, reply);
+ int result = tcp.sendAndReceive(req, reply);
if (result != e_tcp_success) {
std::cout << tcp.errorString(result) << std::endl;
return e_tcp_error_conn;
@@ -81,7 +85,7 @@ void overrideSetup(LicdSetup *setup, int argc, char *argv[])
}
if (longterm) {
// Longterm operation (add|remove) has to come right after the -L switch, not later
- if (sw == LONGTERM_ADD_OP || sw == LONGTERM_REMOVE_OP) {
+ if (sw == OP_ADD_RESERVATION || sw == OP_REMOVE_RESERVATION) {
setup->set("operation", sw);
longterm = false;
continue;
@@ -133,8 +137,8 @@ void overrideSetup(LicdSetup *setup, int argc, char *argv[])
int doLongtermRequest(LicdSetup *setup)
{
- std::string operation = setup->get("operation"); // utils::trimStr(argv[2]);
- if (operation != LONGTERM_ADD_OP && operation != LONGTERM_REMOVE_OP) {
+ std::string operation = setup->get("operation");
+ if (operation != OP_ADD_RESERVATION && operation != OP_REMOVE_RESERVATION) {
std::string error = "Invalid operation \"" + operation;
error += "\"";
errorAndExit(error);
@@ -148,7 +152,10 @@ int doLongtermRequest(LicdSetup *setup)
std::stringstream request;
request << LONGTERM_REQUEST_CMD << " " << setup->get("operation")
<< " -u " << setup->get("user_id")
- << " -i " << setup->get("license_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")
@@ -190,6 +197,7 @@ void helpAndExit()
<< " -v or --version : Prints out qtlicensetool version\n"
<< " -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"
<< " add|remove <--- Either one needs to be there\n"
diff --git a/src/clienthandler.cpp b/src/clienthandler.cpp
new file mode 100644
index 0000000..789176b
--- /dev/null
+++ b/src/clienthandler.cpp
@@ -0,0 +1,120 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+
+#include "clienthandler.h"
+
+bool ClientHandler::checkLicenseExpiryTime(std::string &reply)
+{
+ std::cout << "Offline - checking validity from license file " << m_request.licenseFile << std::endl;
+ // Open the license file
+ std::string data;
+ if (utils::readFile(data, m_request.licenseFile) != 0) {
+ std::cout << "No license file - rejecting license " << m_request.licenseFile << std::endl;
+ reply = replyString[e_bad_connection];
+ return false;
+ }
+ JsonHandler license(data);
+ // Check license status
+ if (license.get("status") != "true") {
+ std::cout << "License status = false: Rejecting license\n";
+ reply = replyString[e_bad_connection];
+ return false;
+ }
+ // Expiry date. Add 1 day to expiry date to get the end actually at the beginning of the next day
+ std::string expDate = license.get("expiry_date");
+ std::time_t expEpoch = utils::stringToEpoch(expDate.c_str()) + SECS_IN_DAY;
+ // Current date
+ std::time_t current = std::time(0);
+ // See if the time has expire
+ if (current > expEpoch) {
+ // Store the leeway time if applicable
+ if(license.get("leeway_hours") != "") {
+ m_license.leeway_hours = license.getInt("leeway_hours");
+ m_license.current_timestamp = current;
+ m_license.expiry_epoch = expEpoch;
+ }
+ return false;
+ }
+ std::cout << "License granted, expires at " << expDate << std::endl;
+ reply = replyString[e_license_granted];
+ return true;
+}
+
+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;
+ if (cmd == LICENSE_REQUEST_CMD) {
+ m_request.type = RequestType::license_request;
+ } else if (cmd == LONGTERM_REQUEST_CMD) {
+ m_request.type = RequestType::long_term_request;
+ // find either 'add' or 'remove'
+ std::string op = utils::trimStr(cmd.substr(8, cmd.length() -1));
+ if (op != OP_ADD_RESERVATION && op != OP_REMOVE_RESERVATION) {
+ std::cout << "Invalid longterm operation: " << op;
+ return e_bad_request;
+ }
+ m_request.operation = op;
+ } else if (cmd == SERVER_VERSION_CMD) {
+ m_request.type = RequestType::server_version;
+ buildRequestJson();
+ return 0;
+ } else if (cmd == DAEMON_VERSION_CMD) {
+ m_request.type = RequestType::daemon_version;
+ } else if (cmd == RESERVATION_QUERY_CMD) {
+ m_request.type = RequestType::reservation_query;
+ } else {
+ std::cout << "Invalid command: " << cmd << std::endl;
+ return e_bad_request;
+ }
+ // Then cycle through parameters. Start from [1] because [0] is the command
+ for (int i = 1; i < params.size(); i++) {
+ std::string item = params[i];
+ char arg = (char)item[0];
+ std::string val = utils::trimStr(item.substr(1, item.length() - 1));
+ if (val.length() == 0) {
+ std::cout << "No value for argument: -" << arg << std::endl;
+ return e_bad_request;
+ }
+ if (arg == 'a') m_request.appName = utils::strToLower(val);
+ else if (arg == 'v') m_request.appVersion = val;
+ else if (arg == 'u') m_request.userId = val;
+ else if (arg == 'i') m_request.licenseId = val;
+ else if (arg == 'p') m_request.parentReservationId = val;
+ else if (arg == 'r') m_request.runnerType = val;
+ else if (arg == 'e') m_request.email = val;
+ else if (arg == 'l') m_request.serverAddr = val;
+ else {
+ std::cout << "Invalid argument: -" << arg << std::endl;
+ return e_bad_request;
+ }
+ }
+ std::stringstream ss;
+ ss << WORKING_DIR << DIR_SEPARATOR << LICENSE_FILE_PREFIX;
+ ss << m_request.userId << "_" << m_request.licenseId << LICENSE_FILE_EXTENSION;
+ m_request.licenseFile += ss.str();
+ buildRequestJson();
+ return 0;
+}
+
+bool ClientHandler::checkLeewayTime(std::string &reply)
+{
+ // Leeway time granted?
+ if (m_license.leeway_hours == 0) {
+ return false;
+ }
+ // License expired and offline: Allow some leeway time
+ int leewayTimeLeft = m_license.expiry_epoch + (m_license.leeway_hours * SECS_IN_HOUR) - m_license.current_timestamp;
+ if (leewayTimeLeft > 0) {
+ std::stringstream ss;
+ ss << replyString[e_no_conn_leeway]
+ << std::fixed << std::setprecision(1)
+ << (float)leewayTimeLeft / SECS_IN_DAY << " days";
+ reply = ss.str();
+ return true;
+ }
+ return false;
+}
+
diff --git a/src/daemon_clients/clienthandler.h b/src/daemon_clients/clienthandler.h
new file mode 100644
index 0000000..1181294
--- /dev/null
+++ b/src/daemon_clients/clienthandler.h
@@ -0,0 +1,64 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+
+#pragma once
+
+#include <iostream>
+#include <string>
+#include "utils.h"
+#include "commonsetup.h"
+#include "licdsetup.h"
+#include "jsonhandler.h"
+
+class ClientHandler
+{
+ public:
+ ClientHandler(const RequestInfo &request, const LicdSetup &settings) :
+ m_request(request),
+ m_settings(settings)
+ { }
+ 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;
+
+ virtual bool isCachedReservationValid(std::string &reply) = 0;
+ virtual bool isLicenseRequestDue() = 0;
+ virtual int parseAndSaveResponse(std::string &response) = 0;
+ virtual void buildRequestJson() = 0;
+
+ bool hasFloatingLicense() { return m_floatingLicense; }
+ 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; }
+ int getClientType() { return (int)m_request.client; }
+ virtual void release() { return; }
+
+ protected:
+ License m_license;
+ RequestInfo m_request;
+ LicdSetup m_settings;;
+ uint64_t m_updateInterval;
+ bool m_floatingLicense = false;
+
+ bool checkLicenseExpiryTime(std::string &reply);
+ bool checkLeewayTime(std::string &reply);
+};
+
+static std::map<RequestReply, std::string> replyString {
+ {e_bad_request, "ERROR Bad request"},
+ {e_license_granted, "License acquired."},
+ {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_bad_connection, "No connection to server. Try again later."}
+ };
+
+
+
diff --git a/src/daemon_clients/clitoolhandler.h b/src/daemon_clients/clitoolhandler.h
new file mode 100644
index 0000000..a63dd40
--- /dev/null
+++ b/src/daemon_clients/clitoolhandler.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+#pragma once
+
+#include "clienthandler.h"
+
+class CliToolHandler : public virtual ClientHandler {
+
+ public:
+ CliToolHandler(const RequestInfo &request, const LicdSetup &settings)
+ : ClientHandler(request, settings) {}
+
+ bool isLicenseRequestDue() override { return true; }
+ bool isCachedReservationValid(std::string &reply) override { return false; }
+
+ private:
+
+ void buildRequestJson() override
+ {
+ if (m_request.type == RequestType::server_version) {
+ m_request.payload = "";
+ return;
+ }
+ std::stringstream pay;
+ pay << "{";
+ pay<< "\"license_number\":" << "\"" << m_request.licenseId << "\",";
+ pay << "\"user_id\":" << "\"" << m_request.userId << "\",";
+ pay << "\"operation\":" << "\"" << m_request.operation << "\"";
+ pay << "}";
+ m_request.payload = pay.str();
+ }
+
+ int parseAndSaveResponse(std::string &response) override
+ {
+ JsonHandler json(response);
+ std::stringstream ss;
+ std::cout << json.dump(4);
+
+ if (m_request.type == 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") {
+ response = replyString[e_license_pool_full];
+ } 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";
+ response = "Qt License Server v";
+ response += json.get("version");
+ return 0; // Do not touch cached license files pls.
+ }
+ ss << replyString[e_license_granted];
+ ss << " expiry_date=" << json.get("expiry_date");
+ ss << " license_id=" << json.get("license_number");
+ ss << " reservation_id=" << json.get("reservation_id");
+ response = ss.str();
+
+ // Add timestamp into license JSON
+ json.add("last_timestamp", utils::getTimestampNow());
+
+ 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;
+ }
+ return 0;
+ }
+};
diff --git a/src/daemon_clients/cocohandler.h b/src/daemon_clients/cocohandler.h
new file mode 100644
index 0000000..d25b36c
--- /dev/null
+++ b/src/daemon_clients/cocohandler.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+#pragma once
+
+#include "clienthandler.h"
+
+class CocoHandler : public ClientHandler {
+
+ public:
+ CocoHandler(const RequestInfo &request, const LicdSetup &settings)
+ : ClientHandler(request, settings)
+ {
+ m_updateInterval = utils::strToInt(m_settings.get("coco_report_interval"));
+ }
+
+ 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
+ {
+ // TODO
+ return;
+ };
+
+}; \ No newline at end of file
diff --git a/src/daemon_clients/mochandler.h b/src/daemon_clients/mochandler.h
new file mode 100644
index 0000000..d0dc579
--- /dev/null
+++ b/src/daemon_clients/mochandler.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+#pragma once
+
+#include "clienthandler.h"
+
+class MocHandler : virtual public ClientHandler {
+ public:
+ MocHandler(const RequestInfo &request, const LicdSetup &settings)
+ : ClientHandler(request, settings)
+ {
+ m_updateInterval = utils::strToInt(m_settings.get("moc_renewal_interval")) * SECS_IN_HOUR;
+ }
+
+ bool isCachedReservationValid(std::string &reply) override
+ {
+ if (!checkLicenseExpiryTime(reply)) {
+ if (checkLeewayTime(reply)) {
+ return true;
+ }
+ } else {
+ reply = replyString[e_license_granted];
+ return true;
+ }
+ 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 << "\"src\":" << "\"" << m_request.appName << "\",";
+ pay << "\"host_os\":" << "\"" << m_settings.get("host_os") << "\",";
+ pay << "\"src_version\":" << "\"" << m_request.appVersion << "\",";
+ pay << "\"email\":" << "\"" << m_request.email << "\"";
+ pay << "}";
+ m_request.payload = pay.str();
+ }
+
+ bool isLicenseRequestDue() override
+ {
+ std::cout << "MOC calling, checking if renewal is needed\n";
+ // Open the license file
+ std::string data;
+ if (utils::readFile(data, m_request.licenseFile) != 0) {
+ // If there is no license file yet, have to request anyway
+ std::cout << "No license present (" << m_request.licenseFile << ") - requesting license\n";
+ return true;
+ }
+ JsonHandler license(data);
+ if (license.get("status") != "true") {
+ // Cached license not valid
+ return true;
+ }
+ uint64_t timeNow = utils::getTimestampNow();
+ if (timeNow > utils::strToInt(license.get("last_timestamp")) + m_updateInterval) {
+ // Renewal is due
+ std::cout << "Requesting license renewal\n";
+ return true;
+ }
+ std::cout << "Renewal time not due, granting license\n";
+
+ return false;
+ }
+
+ int parseAndSaveResponse(std::string &response) override
+ {
+ JsonHandler json(response);
+ // response JSON is converted to a reply string to the client from now on
+ std::stringstream ss;
+
+ if (json.get("status") != "true") {
+ if (json.get("message") == "License fully reserved") {
+ response = replyString[e_license_pool_full];
+ } else {
+ response = replyString[e_license_rejected];
+ }
+ // Remove the license file and return
+ utils::deleteFile(m_request.licenseFile);
+ return 1;
+ }
+
+ ss << replyString[e_license_granted];
+ ss << " expiry_date=" << json.get("expiry_date");
+ ss << " license_id=" << json.get("license_number");
+ ss << " reservation_id=" << json.get("reservation_id");
+ response = ss.str();
+
+ // Add timestamp into license JSON
+ json.add("last_timestamp", utils::getTimestampNow());
+
+ // Save the license JSON
+ 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;
+ }
+ return 0;
+ }
+
+}; \ No newline at end of file
diff --git a/src/daemon_clients/pluginhandler.h b/src/daemon_clients/pluginhandler.h
new file mode 100644
index 0000000..132f128
--- /dev/null
+++ b/src/daemon_clients/pluginhandler.h
@@ -0,0 +1,77 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+#pragma once
+
+#include "clienthandler.h"
+
+class PluginHandler : public ClientHandler {
+
+ public:
+ PluginHandler(const RequestInfo &request, const LicdSetup &settings)
+ : ClientHandler(request, settings) {}
+
+ bool isLicenseRequestDue() override { return true; } // Pluging does timed requests, so every request counts
+
+ 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 << "\"src\":" << "\"" << m_request.appName << "\",";
+ pay << "\"host_os\":" << "\"" << m_settings.get("host_os") << "\",";
+ pay << "\"src_version\":" << "\"" << m_request.appVersion << "\",";
+ pay << "\"email\":" << "\"" << m_request.email << "\"";
+ //pay << "\"operation\":" << "\"" << m_request.operation << "\"";
+ pay << "}";
+ m_request.payload = pay.str();
+ }
+
+ bool isCachedReservationValid(std::string &reply) override
+ {
+ if (!checkLicenseExpiryTime(reply)) {
+ if (checkLeewayTime(reply)) {
+ return true;
+ }
+ } else {
+ reply = replyString[e_license_granted];
+ return true;
+ }
+ return false;
+ }
+
+ int parseAndSaveResponse(std::string &response) override
+ {
+ JsonHandler json(response);
+ // response JSON is converted to a reply string to the client from now on
+ std::stringstream ss;
+
+ if (json.get("status") != "true") {
+ if (json.get("message") == "License fully reserved") {
+ response = replyString[e_license_pool_full];
+ } else {
+ response = replyString[e_license_rejected];
+ }
+ // Remove the license file and return
+ utils::deleteFile(m_request.licenseFile);
+ return 1;
+ }
+
+ ss << replyString[e_license_granted];
+ ss << " expiry_date=" << json.get("expiry_date");
+ ss << " license_id=" << json.get("license_number");
+ ss << " reservation_id=" << json.get("reservation_id");
+ response = ss.str();
+
+ // Save the license JSON
+ 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;
+ }
+ return 0;
+ }
+
+}; \ No newline at end of file
diff --git a/src/daemon_clients/squishhandler.h b/src/daemon_clients/squishhandler.h
new file mode 100644
index 0000000..366c624
--- /dev/null
+++ b/src/daemon_clients/squishhandler.h
@@ -0,0 +1,90 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+#pragma once
+
+#include "clienthandler.h"
+
+class SquishHandler : public ClientHandler {
+
+ public:
+ SquishHandler(const RequestInfo &request, const LicdSetup &settings)
+ : ClientHandler(request, settings)
+ {
+ m_updateInterval = utils::strToInt(m_settings.get("squish_report_interval"));
+ m_request.operation = OP_ADD_RESERVATION;
+ m_request.startTimestamp = utils::getTimestampNow();
+ }
+
+ bool isLicenseRequestDue() override { return true; }
+ bool isCachedReservationValid(std::string &reply) override { return true; }
+
+ 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 << "}";
+ m_request.payload = pay.str();
+ m_floatingLicense = true;
+ }
+
+ int parseAndSaveResponse(std::string &response) override
+ {
+ JsonHandler json(response);
+ // 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");
+ ss << " license_id=" << json.get("license_number");
+ ss << " reservation_id=" << json.get("reservation_id");
+ response = ss.str();
+ } else {
+ if (json.get("message") == "License fully reserved") {
+ response = replyString[e_license_pool_full];
+ } else {
+ response = replyString[e_license_rejected];
+ }
+ // Do not save the response json, just return
+ return 1;
+ }
+ m_license.message = json.get("message");
+ m_license.license_id = json.get("license_number");
+ 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;
+
+ // Save the JSON, adding timestamp
+ json.add("last_timestamp", timeNow);
+ 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;
+ }
+ return 0;
+ }
+
+ void release() override
+ {
+ m_request.operation = OP_REMOVE_RESERVATION;
+ m_request.stopTimestamp = utils::getTimestampNow();
+ buildRequestJson();
+ }
+}; \ No newline at end of file
diff --git a/src/daemon_clients/squishidehandler.h b/src/daemon_clients/squishidehandler.h
new file mode 100644
index 0000000..a17b2db
--- /dev/null
+++ b/src/daemon_clients/squishidehandler.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+#pragma once
+
+#include "clienthandler.h"
+
+class SquishIdeHandler : public ClientHandler {
+
+ public:
+ SquishIdeHandler(const RequestInfo &request, const LicdSetup &settings)
+ : ClientHandler(request, settings)
+ {
+ m_updateInterval = utils::strToInt(m_settings.get("squish_report_interval"));
+ m_request.operation = OP_ADD_RESERVATION;
+ }
+
+ 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
+ {
+ // TODO
+ return;
+ };
+}; \ No newline at end of file
diff --git a/dummy_licheck.cpp b/src/dummy_licheck.cpp
index e38c627..e38c627 100644
--- a/dummy_licheck.cpp
+++ b/src/dummy_licheck.cpp
diff --git a/httpclient.cpp b/src/httpclient.cpp
index 33329c6..730b310 100644
--- a/httpclient.cpp
+++ b/src/httpclient.cpp
@@ -51,7 +51,6 @@ int HttpClient::sendRequest(std::string &reply, const std::string &payload,
request.authKey = authKey;
request.payload = payload;
-
if (!request.authKey.empty()) {
// Set authorization only if applicable
std::string auth = "Authorization: " + request.authKey;
diff --git a/jsonhandler.cpp b/src/jsonhandler.cpp
index f46fd72..f46fd72 100644
--- a/jsonhandler.cpp
+++ b/src/jsonhandler.cpp
diff --git a/licdsetup.cpp b/src/licdsetup.cpp
index 2594485..2594485 100644
--- a/licdsetup.cpp
+++ b/src/licdsetup.cpp
diff --git a/src/licenser.cpp b/src/licenser.cpp
new file mode 100644
index 0000000..66c4c2d
--- /dev/null
+++ b/src/licenser.cpp
@@ -0,0 +1,280 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+
+#include "licenser.h"
+
+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
+ if (settings->get("hw_id").empty()) {
+ setHwId();
+ }
+
+ if (tcpPort == 0) {
+ tcpPort = utils::strToInt(settings->get("tcp_listening_port"));
+ }
+ m_mocInterval = utils::strToInt(settings->get("moc_renewal_interval")) * 3600; // 3600 = secs in hour
+ // 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("version_query_access_point"));
+ // Start the TCP/IP server
+ m_server = new TcpServer(tcpPort);
+}
+
+Licenser::~Licenser()
+{
+ delete(m_currentClient);
+ delete(settings);
+ delete(m_server);
+ delete(m_http);
+ std::cout << "Daemon stopped." << std::endl;
+}
+
+
+int Licenser::listen()
+{
+ m_infoString = "";
+ int socket = 0; // Placeholder for whatever socket gets active
+ std::string input = m_server->listenToClients(socket);
+ input = utils::trimStr(input);
+ if (input.empty()) {
+ 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);
+ return 0;
+ }
+ std::cout << "Got an 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";
+ if (m_currentClient->isLicenseRequestDue()) {
+ if (sendServerRequest(reply) == e_bad_connection) {
+ // Bad server connection: Check the existing license file for expiry date
+ if (!m_currentClient->isCachedReservationValid(reply)) {
+ reply = replyString[e_bad_connection];
+ }
+ } else {
+ m_currentClient->parseAndSaveResponse(reply);
+ }
+ } else {
+ // No need to contact server
+ reply = replyString[e_license_granted];
+ }
+ }
+ } else {
+ reply = replyString[e_bad_request];
+ }
+ } else {
+ reply = replyString[e_bad_request];
+ }
+
+ if (m_currentClient->hasFloatingLicense()) {
+ // QA tool, Coco or Squish (cLient with floating license): Store it in cache
+ m_floatingClients.push_back(m_currentClient);
+ }
+
+ reply += m_infoString;
+ reply +="\n";
+ m_server->sendResponse(socket, reply);
+ std::cout << "Replied to socket " << socket << ": " << reply << std::endl;
+
+ if (m_floatingClients.size() > 0) {
+ checkReportsDue();
+ }
+ 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)
+ }
+ }
+ return 0;
+}
+
+
+int Licenser::parseInputAndCreateCLient(uint16_t socketId, const std::string &incoming)
+{
+ // This parses client type from the input string and decides which type of client
+ // 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, '-');
+ std::string client;
+ for ( int i = 0; i < paramList.size() ;i++ ) {
+ std::string item = paramList.at(i);
+ if (item[0] == 'a') {
+ client = utils::trimStr(item.substr(1, item.length() -1));
+ break;
+ }
+ }
+ if (client.empty()) {
+ // Make this thing backwards compatible with old qtlicensetool
+ // which does not send -a switch (app name)
+ std::cout << "Warning: '-a' switch not found: Client undefined, assuming it's a CLI Tool" << std::endl;
+ client = QTLICENSETOOL_APP_NAME;
+ }
+ if (client == MOCWRAPPER_APP_NAME) {
+ std::cout << "MOC calling" << std::endl;
+ request.client = ClientType::client_moc;
+ request.updateIntervalSecs = utils::strToInt(settings->get("moc_renewal_interval"));
+ m_currentClient = new MocHandler(request, *settings);
+ } else if (client == CREATOR_APPNAME || client == DESIGN_STUDIO_APP_NAME) {
+ // No need to have them separately - it's a Plugin making the calls for both
+ request.client = ClientType::client_plugin;
+ m_currentClient = new PluginHandler(request, *settings);
+ } else if (client == QTLICENSETOOL_APP_NAME) {
+ request.client = ClientType::client_CLI;
+ m_currentClient = new CliToolHandler(request, *settings);
+ } else if (client == SQUISH_IDE_APP_NAME) {
+ request.client = ClientType::client_squish_ide;
+ m_currentClient = new SquishIdeHandler(request, *settings);
+ } else if (client == SQUISH_APP_NAME) {
+ request.updateIntervalSecs =
+ utils::strToInt(settings->get("squish_report_interval"));
+ request.client = ClientType::client_squish;
+ m_currentClient = new SquishHandler(request, *settings);
+ } else if (client == COCO_APP_NAME) {
+ request.updateIntervalSecs =
+ utils::strToInt(settings->get("coco_report_interval"));
+ request.client = ClientType::client_coco;
+ m_currentClient = new CocoHandler(request, *settings);
+ }
+ else {
+ std::cout << "Warning: Client undefined!" << std::endl;
+ return (int)ClientType::client_undefined;
+ }
+ m_currentClient->params = paramList;
+ return m_currentClient->getClientType();
+}
+
+int Licenser::sendServerRequest(std::string &reply)
+{
+ std::string authKey;
+ 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";
+ }
+ // Send the request
+ if (m_http->sendRequest(reply, request.payload, request.serverAddr, authKey) != 0) {
+ return e_bad_connection;
+ }
+ return e_got_response;
+}
+
+void Licenser::doHmacHashSha256(const std::string &payload, const std::string &secret, std::string &authKey)
+{
+ std::stringstream ss_result;
+ ss_result << "apikey ";
+
+ // Allocate memory for the HMAC
+ std::vector<uint8_t> out(SHA256_HASH_SIZE);
+
+ // Call hmac-sha256 function
+ hmac_sha256(secret.data(), secret.size(), payload.data(), payload.size(),
+ out.data(), out.size());
+
+ // Convert to string with std::hex
+ for (uint8_t x : out) {
+ ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)x;
+ }
+
+ 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()
+{
+ // Open all license files
+ std::string dir = WORKING_DIR;
+ std::string filter = LICENSE_FILE_PREFIX;
+ std::vector<std::string> files = utils::getDirListing(dir, filter);
+
+ std::stringstream reply;
+ reply << "Current reservations: \n";
+ for (auto file : files) {
+ file = DIR_SEPARATOR + file;
+ file = WORKING_DIR + file;
+ std::cout << "File list: " << file << std::endl;
+ std::string data;
+ if (utils::readFile(data, file) != 0) {
+ std::cout << "Couldn't read license file: " << file << std::endl;
+ continue;
+ }
+ JsonHandler json(data);
+ reply << "\n--- License ID " << json.get("license_number") << " ---\n";
+ reply << " User ID: " << json.get("user_id") << std::endl;
+ reply << " Expiry date: " << json.get("expiry_date") << std::endl;
+ reply << " Reservation ID: " << json.get("reservation_id") << std::endl;
+ }
+ return reply.str();
+}
+
+void Licenser::clientDisconnected(int socketId) {
+ int index = -1;
+ ClientHandler *client;
+ for (int i = 0; i < m_floatingClients.size(); i++) {
+ client = m_floatingClients[i];
+ if (client->getSocketId() == socketId) {
+ index = i;
+ m_currentClient = client;
+ 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
+ }
+
+}
+
+
+std::string Licenser::getDaemonVersion()
+{
+ std::string version = "Qt License Daemon (qtlicd) v";
+ version += DAEMON_VERSION;
+ return version;
+}
+
+void Licenser::setHwId() {
+
+ // TODO calculate hwid hash out of MAC, uname etc...
+ // Edit the qtlicd.ini to make it permanent
+ return;
+} \ No newline at end of file
diff --git a/tcpclient.cpp b/src/tcpclient.cpp
index 1922b76..1922b76 100644
--- a/tcpclient.cpp
+++ b/src/tcpclient.cpp
diff --git a/tcpserver.cpp b/src/tcpserver.cpp
index 5ee4e89..b1205ba 100644
--- a/tcpserver.cpp
+++ b/src/tcpserver.cpp
@@ -8,7 +8,6 @@
TcpServer::TcpServer(uint16_t serverPort)
{
int opt = TRUE;
-
// Initialize all m_clientSocket[] to 0 so not checked
for (uint8_t i = 0; i < MAX_CLIENTS; i++) {
m_clientSocket[i] = 0;
@@ -29,9 +28,7 @@ TcpServer::TcpServer(uint16_t serverPort)
perror("socket failed");
exit(EXIT_FAILURE);
}
-
// Set master socket to allow multiple connections
-
if (setsockopt(m_masterSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt,
sizeof(opt)) < 0) {
perror("setsockopt failed");
@@ -50,7 +47,7 @@ TcpServer::TcpServer(uint16_t serverPort)
m_address.sin_addr.s_addr = INADDR_ANY;
m_address.sin_port = htons(serverPort);
- // Bind the socket to localhost port 8888
+ // Bind the socket to localhost
if (bind(m_masterSocket, (struct sockaddr *)&m_address, sizeof(m_address)) < 0) {
doCloseSocket(m_masterSocket);
perror("bind failed");
@@ -149,11 +146,10 @@ std::string TcpServer::listenToClients(int &socket)
// Somebody disconnected, get his details and print
getpeername(sd, (struct sockaddr *)&m_address,
(socklen_t *)&m_addrlen);
- std::cout << "Client disconnected, socket id " << sd << std::endl;
-
// Close the socket and mark as 0 in list for reuse
doCloseSocket(sd);
m_clientSocket[i] = 0;
+ data = "closed";
} else {
// Set the string terminating NULL byte
// on the end of the data read
@@ -176,7 +172,7 @@ int TcpServer::sendResponse(int socketIndex, const std::string &message)
printf("[TcpServer] Send failed\n");
return 1;
}
- doCloseSocket(sd);
- m_clientSocket[socketIndex] = 0;
+ // doCloseSocket(sd);
+ // m_clientSocket[socketIndex] = 0;
return 0;
}
diff --git a/utils.cpp b/src/utils.cpp
index 95c5b66..cb68829 100644
--- a/utils.cpp
+++ b/src/utils.cpp
@@ -4,7 +4,6 @@
*/
#include "utils.h"
-#include "commonsetup.h"
namespace utils
{
@@ -236,8 +235,16 @@ std::vector<std::string> getDirListing(const std::string &directory, const std::
return files;
}
-#include <time.h>
-
+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;
+ }
+ return 0;
+}
std::string getOsName()
{
@@ -288,6 +295,14 @@ time_t stringToEpoch(const char* theTime, const char* format)
return mktime(&tmTime);
}
+uint64_t getTimestampNow()
+{
+ // Get current time
+ struct timeval tp;
+ gettimeofday(&tp, NULL);
+ return (uint64_t)tp.tv_sec;
+}
+
/*
* App-specific utils here (not generic)
*/