client.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. #include <client.hpp>
  2. #include <arpa/inet.h>
  3. #include <netdb.h>
  4. #include <string.h>
  5. #include <sys/socket.h>
  6. #include <sys/types.h>
  7. #include <unistd.h>
  8. #include <functional>
  9. #include <algorithm>
  10. #include <cstring>
  11. #include <QDebug>
  12. #include <QByteArray>
  13. #include <iostream>
  14. #include <vector>
  15. #include <future>
  16. #include <headers/kmessage_codec.hpp>
  17. #include <headers/json.hpp>
  18. #include <headers/util.hpp>
  19. using namespace KData;
  20. using json = nlohmann::json;
  21. static const int MAX_BUFFER_SIZE = 2048;
  22. static const int MAX_PACKET_SIZE = 4096;
  23. static const int HEADER_SIZE = 4;
  24. flatbuffers::FlatBufferBuilder builder(1024);
  25. /**
  26. * @brief Client::createMessageHandler
  27. * @param cb
  28. * @return
  29. */
  30. Client::MessageHandler Client::createMessageHandler(
  31. std::function<void()> cb) {
  32. return MessageHandler(cb);
  33. }
  34. /**
  35. * @brief Client::Client
  36. * @constructor
  37. * @param parent
  38. * @param count
  39. * @param arguments
  40. */
  41. Client::Client(QWidget *parent, int count, char** arguments) : QDialog(parent), argc(count), argv(arguments), m_client_socket_fd(-1), m_commands({}), executing(false) {
  42. qRegisterMetaType<QVector<QString>>("QVector<QString>");
  43. }
  44. /**
  45. * @brief Client::~Client
  46. * @destructor
  47. */
  48. Client::~Client() {
  49. closeConnection();
  50. }
  51. /**
  52. * @brief Client::handleMessages
  53. */
  54. void Client::handleMessages() {
  55. uint8_t receive_buffer[2048];
  56. for (;;) {
  57. memset(receive_buffer, 0, 2048);
  58. ssize_t bytes_received = 0;
  59. bytes_received = recv(m_client_socket_fd, receive_buffer, 2048 - 2, 0);
  60. receive_buffer[2047] = 0;
  61. if (bytes_received == 0) {
  62. break;
  63. }
  64. size_t end_idx = findNullIndex(receive_buffer);
  65. std::string data_string{receive_buffer, receive_buffer + end_idx};
  66. StringVec s_v{};
  67. if (isNewSession(data_string.c_str())) {
  68. m_commands = getArgMap(data_string.c_str());
  69. for (const auto& [k, v] : m_commands) {
  70. s_v.push_back(v.data());
  71. }
  72. emit Client::messageReceived(COMMANDS_UPDATE_TYPE, "", s_v);
  73. } else if (serverWaitingForFile(data_string.c_str())) {
  74. sendFileEncoded(outgoing_file);
  75. } else if (isEvent(data_string.c_str())) {
  76. QString event = getEvent(data_string.c_str());
  77. QVector<QString> args = getArgs(data_string.c_str());
  78. emit Client::messageReceived(EVENT_UPDATE_TYPE, event, args);
  79. if (isUploadCompleteEvent(event.toUtf8().constData())) {
  80. outgoing_file.clear();
  81. std::string operation_string = createOperation("Schedule", m_task);
  82. sendEncoded(operation_string);
  83. }
  84. }
  85. std::string formatted_json = getJsonString(data_string);
  86. emit Client::messageReceived(MESSAGE_UPDATE_TYPE, QString::fromUtf8(formatted_json.data(), formatted_json.size()), {});
  87. }
  88. memset(receive_buffer, 0, 2048);
  89. ::close(m_client_socket_fd);
  90. // ::shutdown(m_client_socket_fd, SHUT_RDWR);
  91. }
  92. /**
  93. * @brief Client::start
  94. * @return A meaningless integer
  95. */
  96. void Client::start() {
  97. if (m_client_socket_fd == -1) {
  98. m_client_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  99. if (m_client_socket_fd != -1) {
  100. sockaddr_in server_socket;
  101. char* end;
  102. server_socket.sin_family = AF_INET;
  103. auto port_value = strtol(argv[2], &end, 10);
  104. if (port_value < 0 || end == argv[2]) {
  105. return;
  106. }
  107. int socket_option = 1;
  108. // Free up the port to begin listening again
  109. setsockopt(m_client_socket_fd, SOL_SOCKET, SO_REUSEADDR, &socket_option,
  110. sizeof(socket_option));
  111. server_socket.sin_port = htons(port_value);
  112. inet_pton(AF_INET, argv[1], &server_socket.sin_addr.s_addr);
  113. if (::connect(m_client_socket_fd, reinterpret_cast<sockaddr*>(&server_socket),
  114. sizeof(server_socket)) != -1) {
  115. std::string start_operation_string = createOperation("start", {});
  116. // Send operation as an encoded message
  117. sendEncoded(start_operation_string);
  118. // Delegate message handling to its own thread
  119. std::function<void()> message_send_fn = [this]() {
  120. this->handleMessages();
  121. };
  122. MessageHandler message_handler = createMessageHandler(message_send_fn);
  123. // Handle received messages on separate thread
  124. std::thread (message_handler).detach();
  125. } else {
  126. qDebug() << errno;
  127. ::close(m_client_socket_fd);
  128. }
  129. } else {
  130. qDebug() << "Failed to create new connection";
  131. }
  132. } else {
  133. qDebug() << "Connection already in progress";
  134. }
  135. }
  136. /**
  137. * @brief Client::sendMessage
  138. * @param s[in] <const QString&> The message to send
  139. */
  140. void Client::sendMessage(const QString& s) {
  141. if (m_client_socket_fd != -1) {
  142. std::string json_string {"{\"type\":\"custom\", \"message\": \""};
  143. json_string += s.toUtf8().data();
  144. json_string += "\", \"args\":\"placeholder\"}";
  145. // Send custom message as an encoded message
  146. sendEncoded(json_string);
  147. } else {
  148. qDebug() << "You must first open a connection";
  149. }
  150. }
  151. void Client::sendEncoded(std::string message) {
  152. std::vector<uint8_t> fb_byte_vector{message.begin(), message.end()};
  153. auto byte_vector = builder.CreateVector(fb_byte_vector);
  154. auto k_message = CreateMessage(builder, 69, byte_vector);
  155. builder.Finish(k_message);
  156. uint8_t* encoded_message_buffer = builder.GetBufferPointer();
  157. uint32_t size = builder.GetSize();
  158. qDebug() << "Size is " << size;
  159. uint8_t send_buffer[MAX_BUFFER_SIZE];
  160. memset(send_buffer, 0, MAX_BUFFER_SIZE);
  161. send_buffer[0] = (size & 0xFF) >> 24;
  162. send_buffer[1] = (size & 0xFF) >> 16;
  163. send_buffer[2] = (size & 0xFF) >> 8;
  164. send_buffer[3] = (size & 0xFF);
  165. std::memcpy(send_buffer + 4, encoded_message_buffer, size);
  166. qDebug() << "Ready to send:";
  167. std::string message_to_send{};
  168. for (unsigned int i = 0; i < (size + 4); i++) {
  169. message_to_send += (char)*(send_buffer + i);
  170. }
  171. qDebug() << message_to_send.c_str();
  172. // Send start operation
  173. ::send(m_client_socket_fd, send_buffer, size + 4, 0);
  174. builder.Clear();
  175. }
  176. void Client::sendPackets(uint8_t* data, int size) {
  177. uint32_t total_size = static_cast<uint32_t>(size + HEADER_SIZE);
  178. uint32_t total_packets = static_cast<uint32_t>(ceil(
  179. static_cast<double>(
  180. static_cast<double>(total_size) / static_cast<double>(MAX_PACKET_SIZE)) // total size / packet
  181. )
  182. );
  183. uint32_t idx = 0;
  184. for (; idx < total_packets; idx++) {
  185. bool is_first_packet = (idx == 0);
  186. bool is_last_packet = (idx == (total_packets - 1));
  187. if (is_first_packet) {
  188. uint32_t first_packet_size =
  189. std::min(size + HEADER_SIZE, MAX_PACKET_SIZE);
  190. uint8_t packet[first_packet_size];
  191. packet[0] = (total_size >> 24) & 0xFF;
  192. packet[1] = (total_size >> 16) & 0xFF;
  193. packet[2] = (total_size >> 8) & 0xFF;
  194. packet[3] = (total_size) & 0xFF;
  195. std::memcpy(packet + HEADER_SIZE, data, first_packet_size - HEADER_SIZE);
  196. /**
  197. * SEND PACKET !!!
  198. */
  199. ::send(m_client_socket_fd, packet, first_packet_size, 0);
  200. if (is_last_packet) {
  201. break;
  202. }
  203. continue;
  204. }
  205. int offset = (idx * MAX_PACKET_SIZE) - HEADER_SIZE;
  206. uint32_t packet_size = std::min(size - offset, MAX_PACKET_SIZE);
  207. uint8_t packet[packet_size];
  208. std::memcpy(packet, data + offset, packet_size);
  209. /**
  210. * SEND PACKET !!!
  211. */
  212. ::send(m_client_socket_fd, packet, packet_size, 0);
  213. if (is_last_packet) {
  214. // cleanup
  215. outgoing_file.clear();
  216. }
  217. }
  218. }
  219. void Client::sendFileEncoded(QByteArray bytes) {
  220. sendPackets(reinterpret_cast<uint8_t*>(bytes.data()), bytes.size());
  221. }
  222. void Client::closeConnection() {
  223. if (m_client_socket_fd != -1) {
  224. std::string stop_operation_string = createOperation("stop", {});
  225. // Send operation as an encoded message
  226. sendEncoded(stop_operation_string);
  227. // Clean up socket file descriptor
  228. ::shutdown(m_client_socket_fd, SHUT_RDWR);
  229. ::close(m_client_socket_fd);
  230. m_client_socket_fd = -1;
  231. return;
  232. }
  233. qDebug() << "There is no active connection to close";
  234. }
  235. void Client::setSelectedApp(std::vector<QString> app_names) {
  236. selected_commands.clear();
  237. for (const auto& name : app_names) {
  238. qDebug() << "Matching mask to " << name;
  239. for (const auto& command : m_commands) {
  240. if (command.second.c_str() == name.toUtf8()) {
  241. selected_commands.push_back(command.first);
  242. }
  243. }
  244. }
  245. }
  246. int Client::getSelectedApp() {
  247. if (selected_commands.size() == 1) {
  248. return selected_commands.at(0);
  249. } else {
  250. QMessageBox::warning(this, tr("App Selection Error"), tr("Unable to retrieve app selection"));
  251. }
  252. return -1;
  253. }
  254. QString Client::getAppName(int mask) {
  255. auto app = m_commands.find(mask);
  256. if (app != m_commands.end()) {
  257. return QString{app->second.c_str()};
  258. }
  259. return QString{""};
  260. }
  261. void Client::execute() {
  262. if (!selected_commands.empty()) {
  263. executing = true;
  264. for (const auto& command : selected_commands) {
  265. auto message = getAppName(command) + " pending";
  266. emit Client::messageReceived(PROCESS_REQUEST_TYPE, message, {});
  267. std::string execute_operation = createOperation("Execute", {std::to_string(command)});
  268. sendEncoded(execute_operation);
  269. }
  270. }
  271. }
  272. void Client::scheduleTask(std::vector<std::string> task_args, bool file_pending) {
  273. if (file_pending) {
  274. m_task = task_args;
  275. } else {
  276. qDebug() << "Requesting a task to be scheduled";
  277. std::string operation_string = createOperation("Schedule", task_args);
  278. sendEncoded(operation_string);
  279. }
  280. }
  281. void Client::sendFile(QByteArray bytes) {
  282. if (outgoing_file.isNull()) {
  283. std::string send_file_operation = createOperation("FileUpload", {});
  284. int size = bytes.size();
  285. qDebug() << size << " bytes to send";
  286. sendEncoded(send_file_operation);
  287. outgoing_file = bytes;
  288. } else {
  289. qDebug() << "Outgoing file buffer is not ready";
  290. }
  291. }