From 2e9689eaa4ee0a931286d42234edc9fd4006e3b4 Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Tue, 18 May 2021 15:12:50 +1000 Subject: [PATCH 1/7] Split up tcp connection into server creation and client connection functions --- shared/utility/tcp.hpp | 68 +++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/shared/utility/tcp.hpp b/shared/utility/tcp.hpp index 69603d3ec..52b1af410 100644 --- a/shared/utility/tcp.hpp +++ b/shared/utility/tcp.hpp @@ -29,6 +29,7 @@ #include /* definition of inet_ntoa */ #include /* definition of gethostbyname */ #include /* definition of struct sockaddr_in */ + #include /* definition of poll and pollfd */ #include #include #include /* definition of close */ @@ -59,8 +60,8 @@ inline int create_socket_server(const int& port) { } #endif // create the socket - const int sfd = socket(AF_INET, SOCK_STREAM, 0); - if (sfd == -1) { + const int server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd == -1) { std::cerr << "Cannot create socket" << std::endl; return -1; } @@ -73,39 +74,72 @@ inline int create_socket_server(const int& port) { address.sin_addr.s_addr = INADDR_ANY; // bind to port - if (bind(sfd, reinterpret_cast(&address), sizeof(sockaddr)) == -1) { + if (bind(server_fd, reinterpret_cast(&address), sizeof(sockaddr)) == -1) { std::cerr << "Cannot bind port " << port << std::endl; - close_socket(sfd); + close_socket(server_fd); return -1; } // listen for connections - if (listen(sfd, 1) == -1) { + if (listen(server_fd, 1) == -1) { std::cerr << "Cannot listen for connections" << std::endl; - close_socket(sfd); + close_socket(server_fd); return -1; } std::cerr << "Waiting for a connection on port " << port << " ..." << std::endl; + return server_fd; +} + +inline int check_for_connection(const int& server_fd, const int& port) { + + // Setup the polling data + pollfd fds; + fds.fd = server_fd; + fds.events = POLLIN | POLLPRI; // Check for data to read and urgent data to read + fds.revents = 0; + + // Poll the server fd to see if there is any data to read + const int num_ready = poll(&fds, 1, 0); + + // Polling failed + if (num_ready < 0) { + std::cerr << "Error: Polling of TCP connection failed: " << strerror(errno) << std::endl; + return -1; + } + + // We have an incoming connection + else if (num_ready > 0) { #ifdef _WIN32 - int asize = sizeof(sockaddr_in); + int asize = sizeof(sockaddr_in); #else - socklen_t asize = sizeof(sockaddr_in); + socklen_t asize = sizeof(sockaddr_in); #endif - sockaddr_in client; - const int cfd = accept(sfd, reinterpret_cast(&client), &asize); + // Accept the connection + sockaddr_in client; + const int client_fd = accept(server_fd, reinterpret_cast(&client), &asize); - if (cfd == -1) { - std::cerr << "Cannot accept client" << std::endl; - close_socket(sfd); - } - else { + // Failed to accept the connection + if (client_fd == -1) { + std::cerr << "Error: Cannot accept client connection on port " << port << ": " << strerror(errno) + << std::endl; + close_socket(server_fd); + return -1; + } + + // Get client information const hostent* client_info = gethostbyname(inet_ntoa(client.sin_addr)); - std::cerr << "Accepted connection from: " << client_info->h_name << std::endl; + std::cerr << "Accepted connection on port " << port << " from: " << client_info->h_name << std::endl; + + // Return the client fd + return client_fd; } - return cfd; + std::cerr << "Waiting for a connection on port " << port << " ..." << std::endl; + + // Nothing yet + return 0; } } // namespace utility::tcp From 1bbc5b80966d682179e565e568e86e62d5c27d6a Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Tue, 18 May 2021 15:16:57 +1000 Subject: [PATCH 2/7] Tidy up includes --- shared/utility/tcp.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/utility/tcp.hpp b/shared/utility/tcp.hpp index 52b1af410..bef128e8f 100644 --- a/shared/utility/tcp.hpp +++ b/shared/utility/tcp.hpp @@ -30,9 +30,8 @@ #include /* definition of gethostbyname */ #include /* definition of struct sockaddr_in */ #include /* definition of poll and pollfd */ - #include - #include - #include /* definition of close */ + #include /* definition of socket, accept, listen, and bind */ + #include /* definition of close */ #endif namespace utility::tcp { From 400f5c57a755c8865eb471f7eae25de6e884d04d Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Tue, 18 May 2021 15:18:23 +1000 Subject: [PATCH 3/7] Use poll-based connection accepting and switch to poll instead of select --- .../nugus_controller/nugus_controller.cpp | 158 ++++++++++-------- 1 file changed, 92 insertions(+), 66 deletions(-) diff --git a/controllers/nugus_controller/nugus_controller.cpp b/controllers/nugus_controller/nugus_controller.cpp index b8f6ec8b8..485c23570 100644 --- a/controllers/nugus_controller/nugus_controller.cpp +++ b/controllers/nugus_controller/nugus_controller.cpp @@ -17,12 +17,10 @@ * Copyright 2021 NUbots */ -// You may need to add webots include files such as -// , , etc. -// and/or add some other includes #include #include #include +#include /* definition of poll and pollfd */ #include #include #include @@ -36,11 +34,10 @@ using namespace utility::tcp; class NUgus : public webots::Robot { public: NUgus(const int& time_step, const int& server_port) - : time_step(time_step), server_port(server_port), tcp_fd(create_socket_server(server_port)) { - send(tcp_fd, "Welcome", 8, 0); - } + : time_step(time_step), server_port(server_port), server_fd(create_socket_server(server_port)), client_fd(-1) {} ~NUgus() { - close_socket(tcp_fd); + close_socket(client_fd); + close_socket(server_fd); } void run() { @@ -48,71 +45,98 @@ class NUgus : public webots::Robot { uint32_t current_num = 1; while (step(time_step) != -1) { - // Don't bother doing anything unless we have an active TCP connection - if (tcp_fd == -1) { - std::cerr << "Error: Failed to start TCP server, retrying ..." << std::endl; - tcp_fd = create_socket_server(server_port); - send(tcp_fd, "Welcome", 8, 0); - continue; - } - - // Setup arguments for select call - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(tcp_fd, &rfds); - timeval timeout = {0, 0}; - - // Watch TCP file descriptor to see when it has input. - // No wait - polling as fast as possible - int num_ready = select(tcp_fd + 1, &rfds, nullptr, nullptr, &timeout); - if (num_ready < 0) { - std::cerr << "Error: Polling of TCP connection failed: " << strerror(errno) << std::endl; - continue; - } - else if (num_ready > 0) { - // Wire format - // unit32_t Nn message size in bytes. The bytes are in network byte order (big endian) - // uint8_t * Nn the message - uint32_t Nn; - if (recv(tcp_fd, &Nn, sizeof(Nn), 0) != sizeof(Nn)) { - std::cerr << "Error: Failed to read message size from TCP connection: " << strerror(errno) - << std::endl; - continue; + // Make sure we have a server + if (server_fd == -1) { + std::cerr << "Error: Lost TCP server, retrying ..." << std::endl; + server_fd = create_socket_server(server_port); + + // If we had to recreate the server then the client is no longer valid + if (client_fd != -1) { + close_socket(client_fd); + client_fd = -1; } + } - // Covert to host endianness, which might be different to network endianness - uint32_t Nh = ntohl(Nn); + // Make sure we have an active TCP connection + if (server_fd != -1 && client_fd == -1) { + std::cerr << "Warning: No active TCP connection, retrying ..." << std::endl; + client_fd = check_for_connection(server_fd, server_port); - std::vector data(Nh, 0); - if (recv(tcp_fd, data.data(), Nh, 0) != Nh) { - std::cerr << "Error: Failed to read message from TCP connection: " << strerror(errno) << std::endl; - continue; + // There was an error accepting the new connection, our server is no longer valid + if (client_fd < 0) { + server_fd = -1; } - - // Parse message data - controller::nugus::RobotControl msg; - if (!msg.ParseFromArray(data.data(), Nh)) { - std::cerr << "Error: Failed to parse serialised message" << std::endl; - continue; + // No new connection came in, we are still waiting + else if (client_fd == 0) { + client_fd = -1; } + // Send our welcome message + else { + send(client_fd, "Welcome", 8, 0); + } + } - // Read out the current message counter from the message - current_num = msg.num(); - - // Send a message to the client - msg.set_num(current_num); - - Nh = msg.ByteSizeLong(); - data.resize(Nh); - msg.SerializeToArray(data.data(), Nh); - - Nn = htonl(Nh); - - if (send(tcp_fd, &Nn, sizeof(Nn), 0) < 0) { - std::cerr << "Error: Failed to send data over TCP connection: " << strerror(errno) << std::endl; + // Server is good and client is good + if (server_fd != -1 && client_fd != -1) { + // Setup arguments for poll call + pollfd fds; + fds.fd = client_fd; + fds.events = POLLIN | POLLPRI; // Check for data to read and urgent data to read + fds.revents = 0; + + // Watch TCP file descriptor to see when it has input. + // No wait - polling as fast as possible + int num_ready = poll(&fds, 1, 0); + if (num_ready < 0) { + std::cerr << "Error: Polling of TCP connection failed: " << strerror(errno) << std::endl; + continue; } - else if (send(tcp_fd, data.data(), data.size(), 0) < 0) { - std::cerr << "Error: Failed to send data over TCP connection: " << strerror(errno) << std::endl; + else if (num_ready > 0) { + // Wire format + // unit32_t Nn message size in bytes. The bytes are in network byte order (big endian) + // uint8_t * Nn the message + uint32_t Nn; + if (recv(client_fd, &Nn, sizeof(Nn), 0) != sizeof(Nn)) { + std::cerr << "Error: Failed to read message size from TCP connection: " << strerror(errno) + << std::endl; + continue; + } + + // Covert to host endianness, which might be different to network endianness + uint32_t Nh = ntohl(Nn); + + std::vector data(Nh, 0); + if (recv(client_fd, data.data(), Nh, 0) != Nh) { + std::cerr << "Error: Failed to read message from TCP connection: " << strerror(errno) + << std::endl; + continue; + } + + // Parse message data + controller::nugus::RobotControl msg; + if (!msg.ParseFromArray(data.data(), Nh)) { + std::cerr << "Error: Failed to parse serialised message" << std::endl; + continue; + } + + // Read out the current message counter from the message + current_num = msg.num(); + + // Send a message to the client + msg.set_num(current_num); + + Nh = msg.ByteSizeLong(); + data.resize(Nh); + msg.SerializeToArray(data.data(), Nh); + + Nn = htonl(Nh); + + if (send(client_fd, &Nn, sizeof(Nn), 0) < 0) { + std::cerr << "Error: Failed to send data over TCP connection: " << strerror(errno) << std::endl; + } + else if (send(client_fd, data.data(), data.size(), 0) < 0) { + std::cerr << "Error: Failed to send data over TCP connection: " << strerror(errno) << std::endl; + } } } } @@ -123,8 +147,10 @@ class NUgus : public webots::Robot { const int time_step; /// TCP server port const int server_port; + /// File descriptor to use for the TCP server + int server_fd; /// File descriptor to use for the TCP connection - int tcp_fd; + int client_fd; }; From a621f7ac221c179bec54dc851bcfd356d9c54264 Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Wed, 19 May 2021 10:33:26 +1000 Subject: [PATCH 4/7] Clean up error handling --- .../nugus_controller/nugus_controller.cpp | 10 ++-- shared/utility/tcp.hpp | 47 +++++++++++++------ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/controllers/nugus_controller/nugus_controller.cpp b/controllers/nugus_controller/nugus_controller.cpp index 485c23570..66e314fe1 100644 --- a/controllers/nugus_controller/nugus_controller.cpp +++ b/controllers/nugus_controller/nugus_controller.cpp @@ -20,7 +20,7 @@ #include #include #include -#include /* definition of poll and pollfd */ +#include // definition of poll and pollfd #include #include #include @@ -51,10 +51,8 @@ class NUgus : public webots::Robot { server_fd = create_socket_server(server_port); // If we had to recreate the server then the client is no longer valid - if (client_fd != -1) { - close_socket(client_fd); - client_fd = -1; - } + close_socket(client_fd); + client_fd = -1; } // Make sure we have an active TCP connection @@ -70,7 +68,7 @@ class NUgus : public webots::Robot { else if (client_fd == 0) { client_fd = -1; } - // Send our welcome message + // We just accepted a new connection, send our welcome message else { send(client_fd, "Welcome", 8, 0); } diff --git a/shared/utility/tcp.hpp b/shared/utility/tcp.hpp index bef128e8f..10603358a 100644 --- a/shared/utility/tcp.hpp +++ b/shared/utility/tcp.hpp @@ -26,12 +26,12 @@ #ifdef _WIN32 #include #else - #include /* definition of inet_ntoa */ - #include /* definition of gethostbyname */ - #include /* definition of struct sockaddr_in */ - #include /* definition of poll and pollfd */ - #include /* definition of socket, accept, listen, and bind */ - #include /* definition of close */ + #include // definition of inet_ntoa + #include // definition of gethostbyname + #include // definition of struct sockaddr_in + #include // definition of poll and pollfd + #include // definition of socket, accept, listen, and bind + #include // definition of close #endif namespace utility::tcp { @@ -53,15 +53,30 @@ inline int create_socket_server(const int& port) { WSADATA info; // Winsock 1.1 - if (WSAStartup(MAKEWORD(1, 1), &info) != 0) { - std::cerr << "Cannot initialize Winsock" << std::endl; - return -1; + int err = WSAStartup(MAKEWORD(1, 1), &info); + switch (err) { + case 0: break; + case WSASYSNOTREADY: + std::cerr << "Error: Cannot initialize Winsock: Network subsystem is not ready for communication (" << err + << ")" << std::endl; + case WSAVERNOTSUPPORTED: + std::cerr << "Error: Cannot initialize Winsock: Winsock version 1.1 is not supported (" << err << ")" + << std::endl; + case WSAEINPROGRESS: + std::cerr << "Error: Cannot initialize Winsock: A blocking operation is currently in progress (" << err + << ")" << std::endl; + case WSAEPROCLIM: + std::cerr << "Error: Cannot initialize Winsock: Process limit exceeded (" << err << ")" << std::endl; + case WSAEFAULT: + std::cerr << "Error: Cannot initialize Winsock: Invalid data pointer (" << err << ")" << std::endl; + default: std::cerr << "Error: Cannot initialize Winsock: Unknown error (" << err << ")" << std::endl; return -1; } + #endif // create the socket const int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd == -1) { - std::cerr << "Cannot create socket" << std::endl; + std::cerr << "Error: Cannot create socket: " << strerror(errno) << std::endl; return -1; } @@ -74,18 +89,20 @@ inline int create_socket_server(const int& port) { // bind to port if (bind(server_fd, reinterpret_cast(&address), sizeof(sockaddr)) == -1) { - std::cerr << "Cannot bind port " << port << std::endl; + std::cerr << "Error: Cannot bind port " << port << ": " << strerror(errno) << std::endl; close_socket(server_fd); return -1; } // listen for connections if (listen(server_fd, 1) == -1) { - std::cerr << "Cannot listen for connections" << std::endl; + std::cerr << "Error: Cannot listen for connections: " << strerror(errno) << std::endl; close_socket(server_fd); return -1; } - std::cerr << "Waiting for a connection on port " << port << " ..." << std::endl; + + // Server is now set up and listening for connections + std::cout << "Waiting for a connection on port " << port << " ..." << std::endl; return server_fd; } @@ -129,13 +146,13 @@ inline int check_for_connection(const int& server_fd, const int& port) { // Get client information const hostent* client_info = gethostbyname(inet_ntoa(client.sin_addr)); - std::cerr << "Accepted connection on port " << port << " from: " << client_info->h_name << std::endl; + std::cout << "Accepted connection on port " << port << " from: " << client_info->h_name << std::endl; // Return the client fd return client_fd; } - std::cerr << "Waiting for a connection on port " << port << " ..." << std::endl; + std::cout << "Waiting for a connection on port " << port << " ..." << std::endl; // Nothing yet return 0; From 96439ad56cc2912f91f6595f2cf1854b5f7d4178 Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Wed, 19 May 2021 11:06:27 +1000 Subject: [PATCH 5/7] Add using statement --- controllers/nugus_controller/nugus_controller.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/controllers/nugus_controller/nugus_controller.cpp b/controllers/nugus_controller/nugus_controller.cpp index 6b5ccb552..7cb259a16 100644 --- a/controllers/nugus_controller/nugus_controller.cpp +++ b/controllers/nugus_controller/nugus_controller.cpp @@ -29,6 +29,7 @@ #include "utility/tcp.hpp" +using utility::tcp::check_for_connection; using utility::tcp::close_socket; using utility::tcp::create_socket_server; From ac9a725ed7231ac7d61775aa7cfc5a2f4d957cf6 Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Wed, 19 May 2021 11:07:10 +1000 Subject: [PATCH 6/7] Update controller creation script --- scripts/create_controller.py | 67 ++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/scripts/create_controller.py b/scripts/create_controller.py index 3c1634b4e..d0cec8cd2 100755 --- a/scripts/create_controller.py +++ b/scripts/create_controller.py @@ -64,11 +64,14 @@ // and/or add some other includes #include #include + #include // definition of poll and pollfd #include #include "utility/tcp.hpp" - using namespace utility::tcp; + using utility::tcp::check_for_connection; + using utility::tcp::close_socket; + using utility::tcp::create_socket_server; // This is the main program of your controller. // It creates an instance of your Robot instance, launches its @@ -85,7 +88,7 @@ } // Load in the TCP port number from the command line and convert to an int - int server_port; + int server_port = 0; try { server_port = std::stoi(argv[1]); } @@ -95,7 +98,7 @@ } // Load in the simulation timestep from the command line and convert to an int - int time_step; + int time_step = 0; try { time_step = std::stoi(argv[2]); } @@ -105,25 +108,67 @@ } // Start the TCP server - int tcp_fd = create_socket_server(server_port); + int server_fd = create_socket_server(server_port); + int client_fd = -1; // Create the Robot instance std::unique_ptr robot = std::make_unique(); // Run the robot controller while (robot->step(time_step) != -1) { - // Don't bother doing anything unless we have an active TCP connection - if (tcp_fd == -1) { - std::cerr << "Error: Failed to start TCP server, retrying ..." << std::endl; - tcp_fd = create_socket_server(server_port); - continue; + // Make sure we have a server + if (server_fd == -1) { + std::cerr << "Error: Lost TCP server, retrying ..." << std::endl; + server_fd = create_socket_server(server_port); + + // If we had to recreate the server then the client is no longer valid + close_socket(client_fd); + client_fd = -1; } - // TODO: Do things .... + // Make sure we have an active TCP connection + if (server_fd != -1 && client_fd == -1) { + std::cerr << "Warning: No active TCP connection, retrying ..." << std::endl; + client_fd = check_for_connection(server_fd, server_port); + + // There was an error accepting the new connection, our server is no longer valid + if (client_fd < 0) { + server_fd = -1; + } + // No new connection came in, we are still waiting + else if (client_fd == 0) { + client_fd = -1; + } + // We just accepted a new connection, send our welcome message + else { + send(client_fd, "Welcome", 8, 0); + } + } + + // Server is good and client is good + if (server_fd != -1 && client_fd != -1) { + // Setup arguments for poll call + pollfd fds; + fds.fd = client_fd; + fds.events = POLLIN | POLLPRI; // Check for data to read and urgent data to read + fds.revents = 0; + + // Watch TCP file descriptor to see when it has input. + // No wait - polling as fast as possible + int num_ready = poll(&fds, 1, 0); + if (num_ready < 0) { + std::cerr << "Error: Polling of TCP connection failed: " << strerror(errno) << std::endl; + continue; + } + else if (num_ready > 0) { + // TODO: Do things .... + } + } } // Stop the TCP server - close_socket(tcp_fd); + close_socket(client_fd); + close_socket(server_fd); return EXIT_SUCCESS; } From 9d39c6cd7239ed6c901ff54f2cf3dc1021aecbfd Mon Sep 17 00:00:00 2001 From: Alex Biddulph Date: Wed, 19 May 2021 11:07:26 +1000 Subject: [PATCH 7/7] Fix formatting --- shared/utility/tcp.hpp | 158 +++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 78 deletions(-) diff --git a/shared/utility/tcp.hpp b/shared/utility/tcp.hpp index b867a4c24..b8aa3bf2b 100644 --- a/shared/utility/tcp.hpp +++ b/shared/utility/tcp.hpp @@ -52,33 +52,35 @@ namespace utility::tcp { // initialize the socket api WSADATA info; - // Winsock 1.1 - int err = WSAStartup(MAKEWORD(1, 1), &info); - switch (err) { - case 0: break; - case WSASYSNOTREADY: - std::cerr << "Error: Cannot initialize Winsock: Network subsystem is not ready for communication (" << err - << ")" << std::endl; - case WSAVERNOTSUPPORTED: - std::cerr << "Error: Cannot initialize Winsock: Winsock version 1.1 is not supported (" << err << ")" - << std::endl; - case WSAEINPROGRESS: - std::cerr << "Error: Cannot initialize Winsock: A blocking operation is currently in progress (" << err - << ")" << std::endl; - case WSAEPROCLIM: - std::cerr << "Error: Cannot initialize Winsock: Process limit exceeded (" << err << ")" << std::endl; - case WSAEFAULT: - std::cerr << "Error: Cannot initialize Winsock: Invalid data pointer (" << err << ")" << std::endl; - default: std::cerr << "Error: Cannot initialize Winsock: Unknown error (" << err << ")" << std::endl; return -1; - } + // Winsock 1.1 + int err = WSAStartup(MAKEWORD(1, 1), &info); + switch (err) { + case 0: break; + case WSASYSNOTREADY: + std::cerr << "Error: Cannot initialize Winsock: Network subsystem is not ready for communication (" + << err << ")" << std::endl; + case WSAVERNOTSUPPORTED: + std::cerr << "Error: Cannot initialize Winsock: Winsock version 1.1 is not supported (" << err << ")" + << std::endl; + case WSAEINPROGRESS: + std::cerr << "Error: Cannot initialize Winsock: A blocking operation is currently in progress (" << err + << ")" << std::endl; + case WSAEPROCLIM: + std::cerr << "Error: Cannot initialize Winsock: Process limit exceeded (" << err << ")" << std::endl; + case WSAEFAULT: + std::cerr << "Error: Cannot initialize Winsock: Invalid data pointer (" << err << ")" << std::endl; + default: + std::cerr << "Error: Cannot initialize Winsock: Unknown error (" << err << ")" << std::endl; + return -1; + } #endif - // create the socket - const int server_fd = socket(AF_INET, SOCK_STREAM, 0); - if (server_fd == -1) { - std::cerr << "Error: Cannot create socket: " << strerror(errno) << std::endl; - return -1; - } + // create the socket + const int server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd == -1) { + std::cerr << "Error: Cannot create socket: " << strerror(errno) << std::endl; + return -1; + } // fill in socket address sockaddr_in address{}; @@ -87,76 +89,76 @@ namespace utility::tcp { address.sin_port = htons((unsigned short) port); address.sin_addr.s_addr = INADDR_ANY; - // bind to port - if (bind(server_fd, reinterpret_cast(&address), sizeof(sockaddr)) == -1) { - std::cerr << "Error: Cannot bind port " << port << ": " << strerror(errno) << std::endl; - close_socket(server_fd); - return -1; - } + // bind to port + if (bind(server_fd, reinterpret_cast(&address), sizeof(sockaddr)) == -1) { + std::cerr << "Error: Cannot bind port " << port << ": " << strerror(errno) << std::endl; + close_socket(server_fd); + return -1; + } - // listen for connections - if (listen(server_fd, 1) == -1) { - std::cerr << "Error: Cannot listen for connections: " << strerror(errno) << std::endl; - close_socket(server_fd); - return -1; - } + // listen for connections + if (listen(server_fd, 1) == -1) { + std::cerr << "Error: Cannot listen for connections: " << strerror(errno) << std::endl; + close_socket(server_fd); + return -1; + } - // Server is now set up and listening for connections - std::cout << "Waiting for a connection on port " << port << " ..." << std::endl; + // Server is now set up and listening for connections + std::cout << "Waiting for a connection on port " << port << " ..." << std::endl; - return server_fd; -} + return server_fd; + } -inline int check_for_connection(const int& server_fd, const int& port) { + inline int check_for_connection(const int& server_fd, const int& port) { - // Setup the polling data - pollfd fds; - fds.fd = server_fd; - fds.events = POLLIN | POLLPRI; // Check for data to read and urgent data to read - fds.revents = 0; + // Setup the polling data + pollfd fds; + fds.fd = server_fd; + fds.events = POLLIN | POLLPRI; // Check for data to read and urgent data to read + fds.revents = 0; - // Poll the server fd to see if there is any data to read - const int num_ready = poll(&fds, 1, 0); + // Poll the server fd to see if there is any data to read + const int num_ready = poll(&fds, 1, 0); - // Polling failed - if (num_ready < 0) { - std::cerr << "Error: Polling of TCP connection failed: " << strerror(errno) << std::endl; - return -1; - } + // Polling failed + if (num_ready < 0) { + std::cerr << "Error: Polling of TCP connection failed: " << strerror(errno) << std::endl; + return -1; + } - // We have an incoming connection - else if (num_ready > 0) { + // We have an incoming connection + else if (num_ready > 0) { #ifdef _WIN32 - int asize = sizeof(sockaddr_in); + int asize = sizeof(sockaddr_in); #else - socklen_t asize = sizeof(sockaddr_in); + socklen_t asize = sizeof(sockaddr_in); #endif - // Accept the connection - sockaddr_in client; - const int client_fd = accept(server_fd, reinterpret_cast(&client), &asize); + // Accept the connection + sockaddr_in client; + const int client_fd = accept(server_fd, reinterpret_cast(&client), &asize); - // Failed to accept the connection - if (client_fd == -1) { - std::cerr << "Error: Cannot accept client connection on port " << port << ": " << strerror(errno) - << std::endl; - close_socket(server_fd); - return -1; - } + // Failed to accept the connection + if (client_fd == -1) { + std::cerr << "Error: Cannot accept client connection on port " << port << ": " << strerror(errno) + << std::endl; + close_socket(server_fd); + return -1; + } - // Get client information - const hostent* client_info = gethostbyname(inet_ntoa(client.sin_addr)); - std::cout << "Accepted connection on port " << port << " from: " << client_info->h_name << std::endl; + // Get client information + const hostent* client_info = gethostbyname(inet_ntoa(client.sin_addr)); + std::cout << "Accepted connection on port " << port << " from: " << client_info->h_name << std::endl; - // Return the client fd - return client_fd; - } + // Return the client fd + return client_fd; + } - std::cout << "Waiting for a connection on port " << port << " ..." << std::endl; + std::cout << "Waiting for a connection on port " << port << " ..." << std::endl; - // Nothing yet - return 0; -} + // Nothing yet + return 0; + } } // namespace utility::tcp