diff options
Diffstat (limited to 'src/tcpserver.cpp')
-rw-r--r-- | src/tcpserver.cpp | 178 |
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; +} |