aboutsummaryrefslogtreecommitdiffstats
path: root/src/tcpserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tcpserver.cpp')
-rw-r--r--src/tcpserver.cpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/tcpserver.cpp b/src/tcpserver.cpp
new file mode 100644
index 0000000..b1205ba
--- /dev/null
+++ b/src/tcpserver.cpp
@@ -0,0 +1,178 @@
+/* Copyright (C) 2022 The Qt Company Ltd.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0
+*/
+
+#include "tcpserver.h"
+
+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;
+ }
+
+#ifdef _WIN32
+ // Initialize Winsock
+ WSADATA wsaData;
+ int iResult = 0;
+ iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
+ if (iResult != NO_ERROR) {
+ wprintf(L"Error at WSAStartup()\n");
+ exit(EXIT_FAILURE);
+ }
+#endif
+ // Create a master socket
+ if ((m_masterSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == 0) {
+ 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");
+ exit(EXIT_FAILURE);
+ }
+ timeval tv {2, 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) {
+ printf("Socket timeout error code: %d\n", ret);
+ perror("Socket timeout failed");
+ }
+
+ // Type of socket created
+ m_address.sin_family = AF_INET;
+ m_address.sin_addr.s_addr = INADDR_ANY;
+ m_address.sin_port = htons(serverPort);
+
+ // Bind the socket to localhost
+ if (bind(m_masterSocket, (struct sockaddr *)&m_address, sizeof(m_address)) < 0) {
+ doCloseSocket(m_masterSocket);
+ perror("bind failed");
+ exit(EXIT_FAILURE);
+ }
+ std::cout << "Listening to port " << serverPort << std::endl;
+ unsigned long mode = 1;
+ //ioctlsocket(m_masterSocket, FIONBIO, &mode);
+ // Try to specify maximum of 3 pending connections for the master socket
+ if (listen(m_masterSocket, 3) < 0) {
+ doCloseSocket(m_masterSocket);
+ perror("listen");
+ exit(EXIT_FAILURE);
+ }
+ m_addrlen = sizeof(m_address);
+
+ // Accept the incoming connection
+ std::cout << "Waiting for connections ...\n";
+}
+
+TcpServer::~TcpServer()
+{
+ doCloseSocket(m_masterSocket);
+ for (uint8_t i = 0; i < MAX_CLIENTS; i++) {
+ doCloseSocket(m_clientSocket[i]);
+ }
+
+}
+
+
+std::string TcpServer::listenToClients(int &socket)
+{
+ std::string data;
+ bool gotData = false;
+ //do {
+ // Clear the socket set
+ FD_ZERO(&m_readfds);
+
+ type_socket max_sd = m_masterSocket;
+
+ // Add master socket to set
+ FD_SET(m_masterSocket, &m_readfds);
+
+ // Add child sockets to set
+ for (int i = 0; i < MAX_CLIENTS; i++) {
+ // Socket descriptor
+ type_socket sd = m_clientSocket[i];
+
+ // If valid socket descriptor then add to read list
+ if (sd > 0)
+ FD_SET(sd, &m_readfds);
+
+ // Highest file descriptor number, need it for the select function
+ if (sd > max_sd)
+ max_sd = sd;
+ }
+ // timeout
+ timeval tv{2, 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);
+
+ if ((activity < 0) && (errno != EINTR)) {
+ std::cout << "select error \n";
+ }
+ // If something happened on the master socket, then its an incoming connection
+ if (FD_ISSET(m_masterSocket, &m_readfds)) {
+ type_socket new_socket;
+ if ((new_socket = accept(m_masterSocket,
+ (struct sockaddr *)&m_address, (socklen_t *)&m_addrlen)) < 0) {
+ perror("accept");
+ exit(EXIT_FAILURE);
+ }
+ // Add new socket to array of sockets
+ for (int i = 0; i < MAX_CLIENTS; i++) {
+ // If position is free
+ if (m_clientSocket[i] == 0) {
+ m_clientSocket[i] = new_socket;
+ std::cout << "New connection - adding to list of sockets with id " << i << std::endl;
+ break;
+ }
+ }
+ }
+ // Else its some IO operation on some other socket
+ for (int i = 0; i < MAX_CLIENTS; i++) {
+ type_socket sd = m_clientSocket[i];
+
+ if (FD_ISSET(sd, &m_readfds)) {
+ // Check if it was for closing , and also read the
+ // incoming message
+#ifdef _WIN32
+ int valread = recv(sd, m_buffer, sizeof(m_buffer), 0);
+#else
+ int valread = read(sd, m_buffer, sizeof(m_buffer));
+#endif
+ if (valread == 0) {
+ // Somebody disconnected, get his details and print
+ getpeername(sd, (struct sockaddr *)&m_address,
+ (socklen_t *)&m_addrlen);
+ // 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
+ gotData = true;
+ m_buffer[valread] = '\0';
+ socket = i;
+ data = m_buffer;
+ }
+ }
+ }
+ //} while (!gotData);
+
+ return data;
+}
+
+int TcpServer::sendResponse(int socketIndex, const std::string &message)
+{
+ type_socket sd = m_clientSocket[socketIndex];
+ if (send(sd, message.c_str(), (int)message.length(), 0) != message.length()) {
+ printf("[TcpServer] Send failed\n");
+ return 1;
+ }
+ // doCloseSocket(sd);
+ // m_clientSocket[socketIndex] = 0;
+ return 0;
+}