diff --git a/Inc/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.hpp b/Inc/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.hpp index b0a6d736e..ca875a0d9 100644 --- a/Inc/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.hpp +++ b/Inc/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.hpp @@ -1,137 +1,153 @@ #pragma once +#include -#include "HALALMock/Services/Communication/Ethernet/EthernetNode.hpp" -#include "HALALMock/Services/Communication/Ethernet/Ethernet.hpp" -#include "HALALMock/Models/Packets/Packet.hpp" -#include "HALALMock/Models/Packets/Order.hpp" -#include "HALALMock/Models/Packets/OrderProtocol.hpp" +#include #include #include -#include -#include -/** -* @brief class that handles a single point to point server client connection, emulating the server side. -* -* The flow of this class goes as follows: -* -* 1. When the constructor is called, the listener is activated and starts working immediately -* -* 2. After a client issues a connection to the ServerSocket and Ethernet#update is executed, the ServerSocket accepts the request -* -* 3. Accepting the request raises an interrupt that calls accept_callback, which closes the listener socket (on server_control_block) and opens the connection socket (on client_control_block) -* -* 4. The connection goes on until one of the ends closes it, which calls the ErrorHandler to send the board into fault as a default behaviour. -* -* @see Ethernet#update -*/ -class ServerSocket : public OrderProtocol{ -private: - void create_server_socket(); - bool configure_server_socket(int& socket); - void listen_for_connection(); - void close_inside_thread(); - bool accept_callback(int& client_fd, sockaddr_in& client_address); - void receive(); - queue tx_packet_buffer; - std::jthread listening_thread; - std::jthread receive_thread; - std::mutex mutex; - int server_socket_fd{-1}; - int client_fd{-1}; - -public: - enum ServerState{ - INACTIVE, - LISTENING, - ACCEPTED, - CLOSING, - CLOSED - }; - - static unordered_map listening_sockets; - IPV4 local_ip; - uint32_t local_port; - IPV4 remote_ip; - ServerState state; - static uint8_t priority; - - struct KeepaliveConfig{ - uint32_t inactivity_time_until_keepalive = TCP_INACTIVITY_TIME_UNTIL_KEEPALIVE; - uint32_t space_between_tries = TCP_SPACE_BETWEEN_KEEPALIVE_TRIES; - uint32_t tries_until_disconnection = TCP_KEEPALIVE_TRIES_UNTIL_DISCONNECTION; - }keepalive_config; - - ServerSocket(); - - - ServerSocket(ServerSocket&& other); - - /** - * @brief ServerSocket constructor that receives the server ip on the net as a binary value. - * - * @param local_ip the server ip on. - * @param local_port the port number that the server listens for connections. - */ - ServerSocket(IPV4 local_ip, uint32_t local_port); - ServerSocket(IPV4 local_ip, uint32_t local_port, uint32_t inactivity_time_until_keepalive, uint32_t space_between_tries, uint32_t tries_until_disconnection); - /** - * @brief ServerSocket constructor that uses the EthernetNode class as a parameter - * - * @param local_node the EthernetNode to listen to - * - * @see EthernetNode - */ - ServerSocket(EthernetNode local_node); - ~ServerSocket(); - - void operator=(ServerSocket&& other); - - /** - * @brief ends the connection between the server and the client. - */ - void close(); - /** - * @brief saves the order data into the tx_packet_buffer so it can be sent when a connection is accepted - * - * @param order the order to send, which contains the data and id of the message - * @return true if the data could be allocated in the buffer, false otherwise - */ - bool add_order_to_queue(Order& order); - - /** - * @brief puts the order data into the tx_packet_buffer and sends all the data in the buffer to the client - * - * @param order the order to send, which contains the data and id of the message - * @return true if the data was sent successfully, false otherwise - */ - bool send_order(Order& order) override{ - if(state != ACCEPTED){ - return false; - } - tx_packet_buffer.push(&order); - send(); - return true; - } - - /** - * @brief sends all the binary data saved in the tx_packet_buffer to the connected client. - * - * This function is the one that actually handles outgoing communication, sending one by one the packets in the tx_packet_buffer - * The messages in the buffer are all immediately sent after calling this function, unless an error of any kind happened, in which case ErrorHandler is raised - */ - void send(); - - /** - * @brief function that returns wether or not a client is connected to the ServerSocket - * - * This functions returns a comparison to the state of the ServerSocket, checking wether or not it is on the ACCEPTED state - * This function is equivalent to doing instance->state == ServerSocket#ACCEPT - * - * @return true if a connection with the client was established, false otherwise - */ - bool is_connected(); - -}; - +#include "HALALMock/Models/Packets/Order.hpp" +#include "HALALMock/Models/Packets/OrderProtocol.hpp" +#include "HALALMock/Models/Packets/Packet.hpp" +#include "HALALMock/Services/Communication/Ethernet/Ethernet.hpp" +#include "HALALMock/Services/Communication/Ethernet/EthernetNode.hpp" +/** + * @brief class that handles a single point to point server client connection, + * emulating the server side. + * + * The flow of this class goes as follows: + * + * 1. When the constructor is called, the listener is activated and starts + * working immediately + * + * 2. After a client issues a connection to the ServerSocket and Ethernet#update + * is executed, the ServerSocket accepts the request + * + * 3. Accepting the request raises an interrupt that calls accept_callback, + * which closes the listener socket (on server_control_block) and opens the + * connection socket (on client_control_block) + * + * 4. The connection goes on until one of the ends closes it, which calls the + * ErrorHandler to send the board into fault as a default behaviour. + * + * @see Ethernet#update + */ +class ServerSocket : public OrderProtocol { + private: + void create_server_socket(); + bool configure_server_socket(int& socket); + void listen_for_connection(); + void close_inside_thread(); + bool accept_callback(int& client_fd, sockaddr_in& client_address); + void receive(); + queue tx_packet_buffer; + std::jthread listening_thread; + std::jthread receive_thread; + std::mutex mutex; + int server_socket_fd{-1}; + int client_fd{-1}; + + public: + enum ServerState { INACTIVE, LISTENING, ACCEPTED, CLOSING, CLOSED }; + + static unordered_map listening_sockets; + IPV4 local_ip; + uint32_t local_port; + IPV4 remote_ip; + ServerState state; + static uint8_t priority; + + struct KeepaliveConfig { + uint32_t inactivity_time_until_keepalive = + TCP_INACTIVITY_TIME_UNTIL_KEEPALIVE; + uint32_t space_between_tries = TCP_SPACE_BETWEEN_KEEPALIVE_TRIES; + uint32_t tries_until_disconnection = + TCP_KEEPALIVE_TRIES_UNTIL_DISCONNECTION; + } keepalive_config; + + ServerSocket(); + + ServerSocket(ServerSocket&& other); + + /** + * @brief ServerSocket constructor that receives the server ip on the net as + * a binary value. + * + * @param local_ip the server ip on. + * @param local_port the port number that the server listens for + * connections. + */ + ServerSocket(IPV4 local_ip, uint32_t local_port); + ServerSocket(IPV4 local_ip, uint32_t local_port, + uint32_t inactivity_time_until_keepalive, + uint32_t space_between_tries, + uint32_t tries_until_disconnection); + /** + * @brief ServerSocket constructor that uses the EthernetNode class as a + * parameter + * + * @param local_node the EthernetNode to listen to + * + * @see EthernetNode + */ + ServerSocket(EthernetNode local_node); + ~ServerSocket(); + + void operator=(ServerSocket&& other); + + /** + * @brief ends the connection between the server and the client. + */ + void close(); + /** + * @brief saves the order data into the tx_packet_buffer so it can be sent + * when a connection is accepted + * + * @param order the order to send, which contains the data and id of the + * message + * @return true if the data could be allocated in the buffer, false + * otherwise + */ + bool add_order_to_queue(Order& order); + + /** + * @brief puts the order data into the tx_packet_buffer and sends all the + * data in the buffer to the client + * + * @param order the order to send, which contains the data and id of the + * message + * @return true if the data was sent successfully, false otherwise + */ + bool send_order(Order& order) override { + if (state != ACCEPTED) { + return false; + } + tx_packet_buffer.push(&order); + send(); + return true; + } + + /** + * @brief sends all the binary data saved in the tx_packet_buffer to the + * connected client. + * + * This function is the one that actually handles outgoing communication, + * sending one by one the packets in the tx_packet_buffer The messages in + * the buffer are all immediately sent after calling this function, unless + * an error of any kind happened, in which case ErrorHandler is raised + */ + void send(); + + /** + * @brief function that returns wether or not a client is connected to the + * ServerSocket + * + * This functions returns a comparison to the state of the ServerSocket, + * checking wether or not it is on the ACCEPTED state This function is + * equivalent to doing instance->state == ServerSocket#ACCEPT + * + * @return true if a connection with the client was established, false + * otherwise + */ + bool is_connected(); +}; \ No newline at end of file diff --git a/Src/HALALMock/Services/Communication/Ethernet/Ethernet.cpp b/Src/HALALMock/Services/Communication/Ethernet/Ethernet.cpp index b4ca8b16f..510df6088 100644 --- a/Src/HALALMock/Services/Communication/Ethernet/Ethernet.cpp +++ b/Src/HALALMock/Services/Communication/Ethernet/Ethernet.cpp @@ -1,68 +1,72 @@ - #include "HALALMock/Services/Communication/Ethernet/Ethernet.hpp" -#include + #include +#include in_addr_t ipaddr, netmask, gw; uint8_t IP_ADDRESS[4], NETMASK_ADDRESS[4], GATEWAY_ADDRESS[4]; bool Ethernet::is_ready = false; bool Ethernet::is_running = false; -void Ethernet::start(string local_ip, string subnet_mask, string gateway){ - start(IPV4(local_ip), IPV4(subnet_mask), IPV4(gateway)); +void Ethernet::start(string local_ip, string subnet_mask, string gateway) { + start(IPV4(local_ip), IPV4(subnet_mask), IPV4(gateway)); } -void Ethernet::start(IPV4 local_ip, IPV4 subnet_mask, IPV4 gateway){ - if(!is_running && is_ready){ - ipaddr = local_ip.address; - netmask = subnet_mask.address; - gw = gateway.address; - IP_ADDRESS[0] = ipaddr & 0xFF; - IP_ADDRESS[1] = (ipaddr >> 8) & 0xFF; - IP_ADDRESS[2] = (ipaddr >> 16) & 0xFF; - IP_ADDRESS[3] = (ipaddr >> 24) & 0xFF; - NETMASK_ADDRESS[0] = netmask & 0xFF; - NETMASK_ADDRESS[1] = (netmask >> 8) & 0xFF; - NETMASK_ADDRESS[2] = (netmask >> 16) & 0xFF; - NETMASK_ADDRESS[3] = (netmask >> 24) & 0xFF; - GATEWAY_ADDRESS[0] = gw & 0xFF; - GATEWAY_ADDRESS[1] = (gw >> 8) & 0xFF; - GATEWAY_ADDRESS[2] = (gw >> 16) & 0xFF; - GATEWAY_ADDRESS[3] = (gw >> 24) & 0xFF; - is_running = true; - }else{ - std::cout<<"Unable to start Ethernet!\n"; - } - - if (not is_ready) { - std::cout<<"Ethernet is not ready\n"; - return; - } +void Ethernet::start(IPV4 local_ip, IPV4 subnet_mask, IPV4 gateway) { + if (!is_running && is_ready) { + ipaddr = local_ip.address; + netmask = subnet_mask.address; + gw = gateway.address; + IP_ADDRESS[0] = ipaddr & 0xFF; + IP_ADDRESS[1] = (ipaddr >> 8) & 0xFF; + IP_ADDRESS[2] = (ipaddr >> 16) & 0xFF; + IP_ADDRESS[3] = (ipaddr >> 24) & 0xFF; + NETMASK_ADDRESS[0] = netmask & 0xFF; + NETMASK_ADDRESS[1] = (netmask >> 8) & 0xFF; + NETMASK_ADDRESS[2] = (netmask >> 16) & 0xFF; + NETMASK_ADDRESS[3] = (netmask >> 24) & 0xFF; + GATEWAY_ADDRESS[0] = gw & 0xFF; + GATEWAY_ADDRESS[1] = (gw >> 8) & 0xFF; + GATEWAY_ADDRESS[2] = (gw >> 16) & 0xFF; + GATEWAY_ADDRESS[3] = (gw >> 24) & 0xFF; + is_running = true; + LOG_INFO("Ethernet started succesfully"); + } else { + LOG_ERROR("Unable to start Ethernet!"); + } + if (not is_ready) { + LOG_ERROR("Ethernet is not ready"); + return; + } } -void Ethernet::inscribe(){ - constexpr static uint8_t number_pin_ethernet = 10; - const static Pin pin_list_ethernet[number_pin_ethernet] = {PA1,PA2,PA7,PB13,PC1,PC4,PC5,PG11,PG0,PG13}; - if(!is_ready){ - for(size_t i = 0; i < number_pin_ethernet; i++){ - EmulatedPin &pin_data = SharedMemory::get_pin(pin_list_ethernet[i]); - if(pin_data.type == PinType::NOT_USED){ - pin_data.type = PinType::Ethernet; - }else{ - std::cout<<"Error inscribing ethernet Pins, PA1,PA2,PA7,PB13,PC1,PC4,PC5,PG11,PG0,PG13 must be free\n"; - return; - } - } - is_ready = true; - }else{ - std::cout<<"Unable to inscribe Ethernet because is already ready!\n"; - } +void Ethernet::inscribe() { + constexpr static uint8_t number_pin_ethernet = 10; + const static Pin pin_list_ethernet[number_pin_ethernet] = { + PA1, PA2, PA7, PB13, PC1, PC4, PC5, PG11, PG0, PG13}; + if (!is_ready) { + for (size_t i = 0; i < number_pin_ethernet; i++) { + EmulatedPin &pin_data = SharedMemory::get_pin(pin_list_ethernet[i]); + if (pin_data.type == PinType::NOT_USED) { + pin_data.type = PinType::Ethernet; + LOG_DEBUG("Pin subscribed succcesfully to Ethernet"); + } else { + LOG_ERROR( + "Error inscribing ethernet Pins, " + "PA1,PA2,PA7,PB13,PC1,PC4,PC5,PG11,PG0,PG13 must be free"); + return; + } + } + } else { + LOG_ERROR("Unable to inscribe Ethernet because is already ready!"); + } } -void Ethernet::update(){ - //I'm going to leave the case is not running so it warn the user to check if you have done inscribed - if(not is_running) { - std::cout<<"Ethernet is not running, check if its been inscribed\n"; - return; - } +void Ethernet::update() { + // I'm going to leave the case is not running so it warn the user to check + // if you have done inscribed + if (not is_running) { + LOG_ERROR("Ethernet is not running, check if its been inscribed"); + return; + } } diff --git a/Src/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.cpp b/Src/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.cpp index 2f9c571f6..c88a1f763 100644 --- a/Src/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.cpp +++ b/Src/HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.cpp @@ -1,103 +1,114 @@ - #include "HALALMock/Services/Communication/Ethernet/TCP/ServerSocket.hpp" +#include "HALALMock/Services/Logger/Logger.hpp" + #define MAX_SIZE_BUFFER 1024 uint8_t ServerSocket::priority = 1; -unordered_map ServerSocket::listening_sockets = {}; +unordered_map ServerSocket::listening_sockets = {}; ServerSocket::ServerSocket() = default; -ServerSocket::ServerSocket(IPV4 local_ip, uint32_t local_port) : local_ip(local_ip),local_port(local_port){ - if(not Ethernet::is_running) { - std::cout<<"ServerSocket: Cannot declare ServerSocket before Ethernet::start()\n"; - return; - } - tx_packet_buffer = {}; - state = INACTIVE; - - create_server_socket();//create _server_socket - //configure server socket - if(!configure_server_socket(this->server_socket_fd)){ - std::cout<<"ServerSocket: Error configuring ServerSocket\n"; - close(); - return; - } - //create listening thread - listening_thread = std::jthread(&ServerSocket::listen_for_connection,this); -} +ServerSocket::ServerSocket(IPV4 local_ip, uint32_t local_port) + : local_ip(local_ip), local_port(local_port) { + if (not Ethernet::is_running) { + LOG_ERROR("Cannot declare ServerSocket before Ethernet::start()"); + return; + } + tx_packet_buffer = {}; + state = INACTIVE; + + create_server_socket(); // create _server_socket + // configure server socket + if (!configure_server_socket(this->server_socket_fd)) { + LOG_ERROR("Unable to configure ServerSocket"); + close(); + return; + } + // create listening thread + listening_thread = std::jthread(&ServerSocket::listen_for_connection, this); +} -ServerSocket::ServerSocket(IPV4 local_ip, uint32_t local_port, uint32_t inactivity_time_until_keepalive, uint32_t space_between_tries, uint32_t tries_until_disconnection): ServerSocket(local_ip, local_port){ - keepalive_config.inactivity_time_until_keepalive = inactivity_time_until_keepalive; - keepalive_config.space_between_tries = space_between_tries; - keepalive_config.tries_until_disconnection = tries_until_disconnection; +ServerSocket::ServerSocket(IPV4 local_ip, uint32_t local_port, + uint32_t inactivity_time_until_keepalive, + uint32_t space_between_tries, + uint32_t tries_until_disconnection) + : ServerSocket(local_ip, local_port) { + keepalive_config.inactivity_time_until_keepalive = + inactivity_time_until_keepalive; + keepalive_config.space_between_tries = space_between_tries; + keepalive_config.tries_until_disconnection = tries_until_disconnection; } -//I don't recommend this constructor -ServerSocket::ServerSocket(ServerSocket&& other) : -tx_packet_buffer(std::move(other.tx_packet_buffer)), -listening_thread(std::move(other.listening_thread)), -receive_thread(std::move(other.receive_thread)), -server_socket_fd(other.server_socket_fd), -client_fd(other.client_fd), -local_ip(move(other.local_ip)), -local_port(move(other.local_port)), -state(other.state) -{ - other.client_fd = -1; - other.server_socket_fd = -1; - listening_sockets[local_port] = this; - tx_packet_buffer = {}; +// I don't recommend this constructor +ServerSocket::ServerSocket(ServerSocket&& other) + : tx_packet_buffer(std::move(other.tx_packet_buffer)), + listening_thread(std::move(other.listening_thread)), + receive_thread(std::move(other.receive_thread)), + server_socket_fd(other.server_socket_fd), + client_fd(other.client_fd), + local_ip(move(other.local_ip)), + local_port(move(other.local_port)), + state(other.state) { + other.client_fd = -1; + other.server_socket_fd = -1; + listening_sockets[local_port] = this; + tx_packet_buffer = {}; } -//not recommended in simulator -void ServerSocket::operator=(ServerSocket&& other){ - local_ip = move(other.local_ip); - local_port = move(other.local_port); - state = other.state; - listening_sockets[local_port] = this; - tx_packet_buffer = {}; - if(not (std::find(OrderProtocol::sockets.begin(), OrderProtocol::sockets.end(), this) != OrderProtocol::sockets.end())) - OrderProtocol::sockets.push_back(this); +// not recommended in simulator +void ServerSocket::operator=(ServerSocket&& other) { + local_ip = move(other.local_ip); + local_port = move(other.local_port); + state = other.state; + listening_sockets[local_port] = this; + tx_packet_buffer = {}; + if (not(std::find(OrderProtocol::sockets.begin(), + OrderProtocol::sockets.end(), + this) != OrderProtocol::sockets.end())) + OrderProtocol::sockets.push_back(this); } -ServerSocket::~ServerSocket(){ - auto it = std::find(OrderProtocol::sockets.begin(), OrderProtocol::sockets.end(), this); - if(it == OrderProtocol::sockets.end()) return; - else OrderProtocol::sockets.erase(it); - close(); +ServerSocket::~ServerSocket() { + auto it = std::find(OrderProtocol::sockets.begin(), + OrderProtocol::sockets.end(), this); + if (it == OrderProtocol::sockets.end()) + return; + else + OrderProtocol::sockets.erase(it); + close(); } -ServerSocket::ServerSocket(EthernetNode local_node) : ServerSocket(local_node.ip,local_node.port){}; +ServerSocket::ServerSocket(EthernetNode local_node) + : ServerSocket(local_node.ip, local_node.port) {}; - -//The ServerSocket will only accept one connection -void ServerSocket::listen_for_connection(){ - if (listen(server_socket_fd, SOMAXCONN) < 0) { - std::cout<<"ServerSocket: Error listening\n"; +// The ServerSocket will only accept one connection +void ServerSocket::listen_for_connection() { + if (listen(server_socket_fd, SOMAXCONN) < 0) { + LOG_ERROR("Unable to listen"); ::close(server_socket_fd); - state = CLOSED; + state = CLOSED; return; } - state = LISTENING; - listening_sockets[local_port] = this; - struct sockaddr_in client_addr; - socklen_t client_len = sizeof(client_addr); - client_fd = accept(server_socket_fd,(struct sockaddr*)&client_addr, &client_len); - if(client_fd < 0){ - std::cout<< "ServerSocket: Error accepting\n"; - close_inside_thread(); - } - if(accept_callback(client_fd,client_addr) == true){ - OrderProtocol::sockets.push_back(this); - }else{ - std::cout<<"ServerSocket: Something went wrong in accept_callback\n"; - } + state = LISTENING; + listening_sockets[local_port] = this; + struct sockaddr_in client_addr; + socklen_t client_len = sizeof(client_addr); + client_fd = + accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_len); + if (client_fd < 0) { + LOG_ERROR("Unable to accept"); + close_inside_thread(); + } + if (accept_callback(client_fd, client_addr) == true) { + OrderProtocol::sockets.push_back(this); + } else { + LOG_ERROR("Something went wrong in accept_callback"); + } } - -void ServerSocket::close(){ - // Clean all descriptors - if (client_fd != -1) { +void ServerSocket::close() { + // Clean all descriptors + if (client_fd != -1) { ::close(client_fd); client_fd = -1; } @@ -105,168 +116,206 @@ void ServerSocket::close(){ ::close(server_socket_fd); server_socket_fd = -1; } - //clean the transmision buffer - while (!tx_packet_buffer.empty()) { + // clean the transmision buffer + while (!tx_packet_buffer.empty()) { tx_packet_buffer.pop(); } - //eliminate the threads - if (state == LISTENING && listening_thread.joinable()) { - listening_thread.join(); - } else if (state == ACCEPTED && receive_thread.joinable()) { - receive_thread.join(); - } - listening_sockets[local_port] = this; - state = CLOSED; + // eliminate the threads + if (state == LISTENING && listening_thread.joinable()) { + listening_thread.join(); + } else if (state == ACCEPTED && receive_thread.joinable()) { + receive_thread.join(); + } + listening_sockets[local_port] = this; + state = CLOSED; } - -bool ServerSocket::add_order_to_queue(Order& order){ - if(state == ACCEPTED){ - return false; - } +bool ServerSocket::add_order_to_queue(Order& order) { + if (state == ACCEPTED) { + return false; + } if (order.get_size() == 0) { - std::cout << "ServerSocket: order is empty\n"; - return false; + LOG_ERROR("Order is empty"); + return false; } { - std::lock_guard lock(mutex); - tx_packet_buffer.push(&order); + std::lock_guard lock(mutex); + tx_packet_buffer.push(&order); } - return true; + return true; } -void ServerSocket::send(){ - - while (!tx_packet_buffer.empty()) { - size_t packet_size; - uint8_t *packet_data; - { - std::lock_guard lock(mutex); - Packet *packet = tx_packet_buffer.front(); - packet_size = packet->get_size(); - packet_data = packet->build(); - } - size_t total_sent = 0; - while(total_sent < packet_size){ - ssize_t sent_bytes = ::send(client_fd, packet_data, packet_size, 0); - if (sent_bytes < 0) { - std::cerr << "Error sending the order\n"; - return; - } - total_sent += sent_bytes; - } - tx_packet_buffer.pop(); +void ServerSocket::send() { + while (!tx_packet_buffer.empty()) { + size_t packet_size; + uint8_t* packet_data; + { + std::lock_guard lock(mutex); + Packet* packet = tx_packet_buffer.front(); + packet_size = packet->get_size(); + packet_data = packet->build(); + } + size_t total_sent = 0; + while (total_sent < packet_size) { + ssize_t sent_bytes = ::send(client_fd, packet_data, packet_size, 0); + if (sent_bytes < 0) { + LOG_ERROR("Unable to send the order"); + return; + } + total_sent += sent_bytes; + } + tx_packet_buffer.pop(); } } - -bool ServerSocket::is_connected(){ - return state == ServerSocket::ServerState::ACCEPTED; + +bool ServerSocket::is_connected() { + return state == ServerSocket::ServerState::ACCEPTED; } -void ServerSocket::create_server_socket(){ - server_socket_fd = socket(AF_INET, SOCK_STREAM, 0); - if(server_socket_fd == -1){ - std::cout<<"ServerSocket: Socket creation failure\n"; - return; - } - //inset the local address and port - struct sockaddr_in server_socket_Address; - server_socket_Address.sin_family = AF_INET; - server_socket_Address.sin_addr.s_addr = local_ip.address; - server_socket_Address.sin_port = htons(local_port); - if(bind(server_socket_fd, (struct sockaddr*)&server_socket_Address, sizeof(server_socket_Address)) < 0){ - std::cout<<"ServerSocket: Bind error\n"; - close(); - return; - } +void ServerSocket::create_server_socket() { + server_socket_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket_fd == -1) { + LOG_ERROR("Socket creation failure"); + return; + } + // inset the local address and port + struct sockaddr_in server_socket_Address; + server_socket_Address.sin_family = AF_INET; + server_socket_Address.sin_addr.s_addr = local_ip.address; + server_socket_Address.sin_port = htons(local_port); + if (bind(server_socket_fd, (struct sockaddr*)&server_socket_Address, + sizeof(server_socket_Address)) < 0) { + LOG_ERROR("Unable to bind"); + close(); + return; + } } -bool ServerSocket::configure_server_socket(int& socket_fd){ - //to reuse local address: - int opt = 1; - if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { - std::cerr << "ServerSocket: Error setting SO_REUSEADDR\n"; - close(); - return false; - } - //disable naggle algorithm - int flag = 1; - if (setsockopt(socket_fd,IPPROTO_TCP,TCP_NODELAY,(char *) &flag, sizeof(int)) < 0){ - std::cout<<"ServerSocket: It has been an error disabling Nagle's algorithm\n"; - return false; - } - //habilitate keepalives +bool ServerSocket::configure_server_socket(int& socket_fd) { + // to reuse local address: + int opt = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < + 0) { + LOG_ERROR("Unable to set SO_REUSEADDR"); + close(); + return false; + } + // disable naggle algorithm + int flag = 1; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, + sizeof(int)) < 0) { + LOG_ERROR("Unable to disable Nagle's algorithm"); + return false; + } + // habilitate keepalives int optval = 1; - if (setsockopt(socket_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) { + if (setsockopt(socket_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, + sizeof(optval)) < 0) { std::cout << "ServerSocket: ERROR configuring KEEPALIVES\n"; + LOG_ERROR("Unable to set KEEPALIVES"); return false; } - // Configure TCP_KEEPIDLE it sets what time to wait to start sending keepalives - //different from lwip to linux - uint32_t tcp_keepidle_time = keepalive_config.inactivity_time_until_keepalive; - if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle_time, sizeof(tcp_keepidle_time)) < 0) { - std::cout << "ServerSocket: Error configuring TCP_KEEPIDLE\n"; + // Configure TCP_KEEPIDLE it sets what time to wait to start sending + // keepalives + // different from lwip to linux + uint32_t tcp_keepidle_time = + keepalive_config.inactivity_time_until_keepalive; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle_time, + sizeof(tcp_keepidle_time)) < 0) { + LOG_ERROR("Unable to set TCP_KEEPIDLE"); return false; } - //interval between keepalives + // interval between keepalives uint32_t keep_interval_time = keepalive_config.space_between_tries; - if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval_time, sizeof(keep_interval_time)) < 0) { - std::cout << "ServerSocket: Error configuring TCP_KEEPINTVL\n"; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval_time, + sizeof(keep_interval_time)) < 0) { + LOG_ERROR("Unable to set TCP_KEEPINTVL"); return false; } - // Configure TCP_KEEPCNT (number keepalives are send before considering the connection down) - uint32_t keep_cnt = keepalive_config.tries_until_disconnection; - if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_cnt, sizeof(keep_cnt)) < 0) { - std::cout << "ServerSocket: Error to configure TCP_KEEPCNT\n"; + // Configure TCP_KEEPCNT (number keepalives are send before considering the + // connection down) + uint32_t keep_cnt = keepalive_config.tries_until_disconnection; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_cnt, + sizeof(keep_cnt)) < 0) { + LOG_ERROR("Unable to set TCP_KEEPCNT"); return false; } - return true; + return true; } -bool ServerSocket::accept_callback(int& client_fd, sockaddr_in& client_address){ - if(listening_sockets.contains(local_port) && state == LISTENING){ - state = ACCEPTED; - remote_ip = IPV4(client_address.sin_addr.s_addr); - this->client_fd = client_fd; - //configure_server_socket - configure_server_socket(client_fd); - //create the receive thread - receive_thread = std::jthread(&ServerSocket::receive,this); - return true; - } - return false; +bool ServerSocket::accept_callback(int& client_fd, + sockaddr_in& client_address) { + if (listening_sockets.contains(local_port) && state == LISTENING) { + state = ACCEPTED; + remote_ip = IPV4(client_address.sin_addr.s_addr); + this->client_fd = client_fd; + // configure_server_socket + configure_server_socket(client_fd); + // create the receive thread + receive_thread = std::jthread(&ServerSocket::receive, this); + return true; + } + return false; } -void ServerSocket::receive(){ - while (state == ACCEPTED) { - uint8_t buffer[MAX_SIZE_BUFFER]; // Buffer for the data +void ServerSocket::receive() { + while (state == ACCEPTED) { + uint8_t buffer[MAX_SIZE_BUFFER]; // Buffer for the data ssize_t received_bytes = ::recv(client_fd, buffer, sizeof(buffer), 0); - if(received_bytes > 0) { - uint8_t* received_data = new uint8_t[received_bytes]; - std::memcpy(received_data,buffer,received_bytes); - Order::process_data(this, received_data); - delete[] received_data; - }else{ - std::cout << "ServerSocket: Error receiving the data or Client Disconnected, Closing... \n"; - state = CLOSING; - close_inside_thread(); - return; - } + if (received_bytes > 0) { + uint8_t* received_data = new uint8_t[received_bytes]; + std::memcpy(received_data, buffer, received_bytes); + Order::process_data(this, received_data); + delete[] received_data; + } else { + LOG_WARNING( + "Unable to receive the data or Client Disconnected, " + "closing..."); + state = CLOSING; + close_inside_thread(); + return; + } } } -void ServerSocket::close_inside_thread(){ - //close descriptors - if(server_socket_fd >= 0){ - ::close(server_socket_fd); - } - if(client_fd >= 0){ - ::close(client_fd); - } - //clean the transmissions buffers - { - std::lock_guard lock(mutex); - while (!tx_packet_buffer.empty()) { - tx_packet_buffer.pop(); - } - } - listening_sockets[local_port] = this; - state = CLOSED; +void ServerSocket::close_inside_thread() { + // close descriptors + if (server_socket_fd >= 0) { + ::close(server_socket_fd); + } + if (client_fd >= 0) { + ::close(client_fd); + } + // clean the transmissions buffers + { + std::lock_guard lock(mutex); + while (!tx_packet_buffer.empty()) { + tx_packet_buffer.pop(); + } + } + listening_sockets[local_port] = this; + state = CLOSED; } - +void ServerSocket::configure_server_socket_and_listen() { + create_server_socket(); + if (!configure_server_socket()) { + LOG_ERROR("Can't configure ServerSocket"); + close(); + return; + } + if (listen(server_socket_fd, SOMAXCONN) < 0) { + LOG_ERROR("Can't listen"); + close(); + return; + } + state = LISTENING; + listening_sockets[local_port] = this; + // create a thread to listen + listening_thread = std::jthread[&]() { + // solo aceptamos una conexion + struct sockaddr_in client_addr; + socklen_t client_len = sizeof(client_addr); + client_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, + &client_len); + if (client_fd > 0) { + if (!accept_callback(client_fd, client_addr)) { + LOG_ERROR("Something went wrong in accept_callback"); + } else { + OrderProtocol::sockets.push_back(this); + } \ No newline at end of file diff --git a/Src/HALALMock/Services/Communication/Ethernet/TCP/Socket.cpp b/Src/HALALMock/Services/Communication/Ethernet/TCP/Socket.cpp index 1e4a6f4d5..8042d84d0 100644 --- a/Src/HALALMock/Services/Communication/Ethernet/TCP/Socket.cpp +++ b/Src/HALALMock/Services/Communication/Ethernet/TCP/Socket.cpp @@ -1,245 +1,283 @@ #include "HALALMock/Services/Communication/Ethernet/TCP/Socket.hpp" #define MAX_SIZE_BUFFER 1024 -std::unordered_map Socket::connecting_sockets = {}; +std::unordered_map Socket::connecting_sockets = {}; +#include "HALALMock/Services/Logger/Logger.hpp" + +#define BUFFER_SIZE 1024 Socket::Socket() = default; -Socket::Socket(Socket&& other):socket_fd(other.socket_fd),remote_port(move(remote_port)),state(other.state){ - other.socket_fd = -1; - EthernetNode remote_node(other.remote_ip, other.remote_port); - connecting_sockets[remote_node] = this; -} -void Socket::operator=(Socket&& other){ - remote_port = move(other.remote_port); - state = other.state; - EthernetNode remote_node(other.remote_ip, other.remote_port); - connecting_sockets[remote_node] = this; - if(std::find(OrderProtocol::sockets.begin(), OrderProtocol::sockets.end(), this) == OrderProtocol::sockets.end()) - OrderProtocol::sockets.push_back(this); -} - -Socket::~Socket(){ - auto it = std::find(OrderProtocol::sockets.begin(), OrderProtocol::sockets.end(), this); - if(it == OrderProtocol::sockets.end()) return; - else OrderProtocol::sockets.erase(it); - close(); -} - -Socket::Socket(IPV4 local_ip, uint32_t local_port, IPV4 remote_ip, uint32_t remote_port,bool use_keep_alive): - local_ip(local_ip), local_port(local_port),remote_ip(remote_ip), remote_port(remote_port),use_keep_alives{use_keep_alive} -{ - if(not Ethernet::is_running) { - std::cout<<"Socket: Cannot declare TCP socket before Ethernet::start()"; - return; - } - state = INACTIVE; - tx_packet_buffer = {}; - if(!create_socket()){ - return; - } - EthernetNode remote_node(remote_ip, remote_port); - if(!configure_socket()){ - std::cout<<"Socket: Error configuring socket\n"; - return; - } - connecting_sockets[remote_node] = this; - connect_attempt(); - OrderProtocol::sockets.push_back(this); -} - -bool Socket::create_socket(){ - //create socket not blocking - socket_fd = ::socket(AF_INET,SOCK_STREAM,0); - //inset the local address and port - struct sockaddr_in socket_Address; - socket_Address.sin_family = AF_INET; - socket_Address.sin_addr.s_addr = local_ip.address; - socket_Address.sin_port = htons(local_port); - if(bind(socket_fd, (struct sockaddr*)&socket_Address, sizeof(socket_Address)) < 0){ - std::cout<<"Socket: Bind error in TCP socket\n"; - ::close(socket_fd); - return false; - } - return true; -} -bool Socket::configure_socket(){ - //disable naggle algorithm - int flag = 1; - if (setsockopt(socket_fd,IPPROTO_TCP,TCP_NODELAY,(char *) &flag, sizeof(int)) < 0){ - std::cout<<"Socket: It has been an error disabling Nagle's algorithm\n"; - ::close(socket_fd); - return false; - } - //make the socket to be reuse - int optval_reuse = 1; - if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval_reuse, sizeof(optval_reuse)) < 0) { - std::cerr << "Socket: Error setting SO_REUSEADDR\n"; +Socket::Socket(Socket&& other) + : socket_fd(other.socket_fd), + remote_port(move(remote_port)), + state(other.state) { + other.socket_fd = -1; + EthernetNode remote_node(other.remote_ip, other.remote_port); + connecting_sockets[remote_node] = this; +} +void Socket::operator=(Socket&& other) { + remote_port = move(other.remote_port); + state = other.state; + EthernetNode remote_node(other.remote_ip, other.remote_port); + connecting_sockets[remote_node] = this; + if (std::find(OrderProtocol::sockets.begin(), OrderProtocol::sockets.end(), + this) == OrderProtocol::sockets.end()) + OrderProtocol::sockets.push_back(this); +} + +Socket::~Socket() { + auto it = std::find(OrderProtocol::sockets.begin(), + OrderProtocol::sockets.end(), this); + if (it == OrderProtocol::sockets.end()) + return; + else + OrderProtocol::sockets.erase(it); + close(); +} + +Socket::Socket(IPV4 local_ip, uint32_t local_port, IPV4 remote_ip, + uint32_t remote_port, bool use_keep_alive) + : local_ip(local_ip), + local_port(local_port), + remote_ip(remote_ip), + remote_port(remote_port), + use_keep_alives{use_keep_alive} { + if (not Ethernet::is_running) { + LOG_ERROR("Unable to declare TCP socket before Ethernet::start()"); + return; + } + state = INACTIVE; + tx_packet_buffer = {}; + if (!create_socket()) { + return; + } + EthernetNode remote_node(remote_ip, remote_port); + if (!configure_socket()) { + LOG_ERROR("Unable to set socket"); + return; + } + connecting_sockets[remote_node] = this; + connect_attempt(); + OrderProtocol::sockets.push_back(this); +} + +bool Socket::create_socket() { + // create socket not blocking + socket_fd = ::socket(AF_INET, SOCK_STREAM, 0); + // inset the local address and port + struct sockaddr_in socket_Address; + socket_Address.sin_family = AF_INET; + socket_Address.sin_addr.s_addr = local_ip.address; + socket_Address.sin_port = htons(local_port); + if (bind(socket_fd, (struct sockaddr*)&socket_Address, + sizeof(socket_Address)) < 0) { + LOG_ERROR("Unable to bind TCP socket"); ::close(socket_fd); return false; } - //habilitate keepalives + return true; +} +bool Socket::configure_socket() { + // disable naggle algorithm + int flag = 1; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, + sizeof(int)) < 0) { + LOG_ERROR("Unable to disable Nagle's algorithm"); + ::close(socket_fd); + return false; + } + // make the socket to be reuse + int optval_reuse = 1; + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval_reuse, + sizeof(optval_reuse)) < 0) { + LOG_ERROR("Unable to set SO_REUSEADDR"); + ::close(socket_fd); + return false; + } + // habilitate keepalives int optval = 1; - if (setsockopt(socket_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) < 0) { - std::cout << "Socket: ERROR configuring KEEPALIVES\n"; + if (setsockopt(socket_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, + sizeof(optval)) < 0) { + LOG_ERROR("Unable to set KEEPALIVES"); ::close(socket_fd); return false; } - // Configure TCP_KEEPIDLE it sets what time to wait to start sending keepalives - // Using the minimum linux keepalives time - uint32_t tcp_keepidle_time = keepalive_config.inactivity_time_until_keepalive; - if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle_time, sizeof(tcp_keepidle_time)) < 0) { - std::cout << "Socket: Error configuring TCP_KEEPIDLE\n"; - ::close(socket_fd); + // Configure TCP_KEEPIDLE it sets what time to wait to start sending + // keepalives + // Using the minimum linux keepalives time + uint32_t tcp_keepidle_time = + keepalive_config.inactivity_time_until_keepalive; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle_time, + sizeof(tcp_keepidle_time)) < 0) { + LOG_ERROR("Unable to set TCP_KEEPIDLE"); + ::close(socket_fd); return false; } - //interval between keepalives + // interval between keepalives uint32_t keep_interval_time = keepalive_config.space_between_tries; - if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval_time, sizeof(keep_interval_time)) < 0) { - std::cout << "Socket: Error configuring TCP_KEEPINTVL\n"; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval_time, + sizeof(keep_interval_time)) < 0) { + LOG_ERROR("Unable to configure TCP_KEEPINTVL"); ::close(socket_fd); return false; } - // Configure TCP_KEEPCNT (number keepalives are send before considering the connection down) - uint32_t keep_cnt = keepalive_config.tries_until_disconnection; - if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_cnt, sizeof(keep_cnt)) < 0) { - std::cout << "Socket: Error to configure TCP_KEEPCNT\n"; + // Configure TCP_KEEPCNT (number keepalives are send before considering the + // connection down) + uint32_t keep_cnt = keepalive_config.tries_until_disconnection; + if (setsockopt(socket_fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_cnt, + sizeof(keep_cnt)) < 0) { + LOG_ERROR("Unable to configure TCP_KEEPCNT"); ::close(socket_fd); return false; } - return true; + return true; } - - -void Socket::connect_attempt(){ - //insert the remote address and port and connect - struct sockaddr_in remote_addr; - remote_addr.sin_family = AF_INET; - remote_addr.sin_addr.s_addr = remote_ip.address; - remote_addr.sin_port = htons(remote_port); - if(connect(socket_fd, (struct sockaddr*)&remote_addr, sizeof(remote_addr)) < 0){ - state = INACTIVE; - return; - } - std::cout<<"Socket: Connection established with the remote socket\n"; - connection_callback(); +void Socket::connect_attempt() { + // insert the remote address and port and connect + struct sockaddr_in remote_addr; + remote_addr.sin_family = AF_INET; + remote_addr.sin_addr.s_addr = remote_ip.address; + remote_addr.sin_port = htons(remote_port); + if (connect(socket_fd, (struct sockaddr*)&remote_addr, + sizeof(remote_addr)) < 0) { + state = INACTIVE; + return; + } + LOG_INFO("Connection established with the remote socket"); + connection_callback(); } -void Socket::connection_callback(){ - EthernetNode remote_node(remote_ip, remote_port); - if(connecting_sockets.contains(remote_node)){ - connecting_sockets.erase(remote_node); - state = CONNECTED; - } - //start receiving - is_receiving = true; - receiving_thread = std::jthread(&Socket::receive, this); +void Socket::connection_callback() { + EthernetNode remote_node(remote_ip, remote_port); + if (connecting_sockets.contains(remote_node)) { + connecting_sockets.erase(remote_node); + state = CONNECTED; + } + // start receiving + is_receiving = true; + receiving_thread = std::jthread(&Socket::receive, this); } -Socket::Socket(IPV4 local_ip, uint32_t local_port, IPV4 remote_ip, uint32_t remote_port, uint32_t inactivity_time_until_keepalive, uint32_t space_between_tries, uint32_t tries_until_disconnection): Socket(local_ip, local_port, remote_ip, remote_port){ - keepalive_config.inactivity_time_until_keepalive = inactivity_time_until_keepalive; - keepalive_config.space_between_tries = space_between_tries; - keepalive_config.tries_until_disconnection = tries_until_disconnection; +Socket::Socket(IPV4 local_ip, uint32_t local_port, IPV4 remote_ip, + uint32_t remote_port, uint32_t inactivity_time_until_keepalive, + uint32_t space_between_tries, uint32_t tries_until_disconnection) + : Socket(local_ip, local_port, remote_ip, remote_port) { + keepalive_config.inactivity_time_until_keepalive = + inactivity_time_until_keepalive; + keepalive_config.space_between_tries = space_between_tries; + keepalive_config.tries_until_disconnection = tries_until_disconnection; } -Socket::Socket(EthernetNode local_node, EthernetNode remote_node):Socket(local_node.ip, local_node.port, remote_node.ip, remote_node.port){} +Socket::Socket(EthernetNode local_node, EthernetNode remote_node) + : Socket(local_node.ip, local_node.port, remote_node.ip, remote_node.port) { +} -void Socket::close(){ - ::close(socket_fd); +void Socket::close() { + ::close(socket_fd); if (is_receiving) { is_receiving = false; if (receiving_thread.joinable()) { - receiving_thread.join(); + receiving_thread.join(); } } - while(!tx_packet_buffer.empty()){ - tx_packet_buffer.pop(); - } - state = CLOSING; + while (!tx_packet_buffer.empty()) { + tx_packet_buffer.pop(); + } + state = CLOSING; + LOG_INFO("Socket has been closed correctly") } -void Socket::reconnect(){ //I'm going to do in reconnect a total reset due to at the end in linux sockets you will have to close the socket and configure to reconnect - connect_attempt(); +void Socket::reconnect() { // I'm going to do in reconnect a total reset due to + // at the end in linux sockets you will have to + // close the socket and configure to reconnect + connect_attempt(); } -void Socket::reset(){ - EthernetNode remote_node(remote_ip, remote_port); - - state = INACTIVE; - close(); - if(!create_socket()){ - return; - } - if(!configure_socket()){ - std::cout<<"Socket: Error configuring socket\n"; - return; - } - if(!connecting_sockets.contains(remote_node)){ - connecting_sockets[remote_node] = this; - } - connect_attempt(); +void Socket::reset() { + EthernetNode remote_node(remote_ip, remote_port); + + state = INACTIVE; + close(); + if (!create_socket()) { + return; + } + if (!configure_socket()) { + LOG_ERROR("Unable to configure socket"); + return; + } + if (!connecting_sockets.contains(remote_node)) { + connecting_sockets[remote_node] = this; + } + connect_attempt(); } +void Socket::reset() { + EthernetNode remote_node(remote_ip, remote_port); + if (!connecting_sockets.contains(remote_node)) { + connecting_sockets[remote_node] = this; + } + state = INACTIVE; + close(); + configure_socket_and_connect(); +} -void Socket::send(){ - std::lock_guard lock(mutex); - while (!tx_packet_buffer.empty()) { - Packet *packet = tx_packet_buffer.front(); +void Socket::send() { + std::lock_guard lock(mutex); + while (!tx_packet_buffer.empty()) { + Packet* packet = tx_packet_buffer.front(); size_t total_sent = 0; - size_t packet_size = packet->get_size(); - uint8_t *packet_data = packet->build(); - while(total_sent < packet_size){ - ssize_t sent_bytes = ::send(socket_fd, packet_data, packet_size, 0); - if (sent_bytes < 0) { - std::cerr << "Socket: Error sending the order\n"; - return; - } - total_sent += sent_bytes; - } - tx_packet_buffer.pop(); - } -} -void Socket::receive(){ + size_t packet_size = packet->get_size(); + uint8_t* packet_data = packet->build(); + while (total_sent < packet_size) { + ssize_t sent_bytes = ::send(socket_fd, packet_data, packet_size, 0); + if (sent_bytes < 0) { + LOG_ERROR("Unable to send the order"); + return; + } + total_sent += sent_bytes; + } + tx_packet_buffer.pop(); + } +} +void Socket::receive() { while (is_receiving) { - uint8_t buffer[MAX_SIZE_BUFFER]; // Buffer for the data - + uint8_t buffer[MAX_SIZE_BUFFER]; // Buffer for the data + ssize_t received_bytes = ::recv(socket_fd, buffer, sizeof(buffer), 0); - if(received_bytes > 0) { - uint8_t* received_data = new uint8_t[received_bytes]; - std::memcpy(received_data,buffer,received_bytes); - Order::process_data(this, received_data); - delete[] received_data; + if (received_bytes > 0) { + uint8_t* received_data = new uint8_t[received_bytes]; + std::memcpy(received_data, buffer, received_bytes); + Order::process_data(this, received_data); + delete[] received_data; - }else if (received_bytes < 0) { + } else if (received_bytes < 0) { std::cout << "Socket: Error receiving data\n"; - state = CLOSING; - ::close(socket_fd); - while(!tx_packet_buffer.empty()){ - tx_packet_buffer.pop(); - } - return; + LOG_ERROR("Unable to receive data"); + state = CLOSING; + ::close(socket_fd); + while (!tx_packet_buffer.empty()) { + tx_packet_buffer.pop(); + } + return; } } } -bool Socket::add_order_to_queue(Order& order){ - if(state == Socket::SocketState::CONNECTED){ - return false; - } +bool Socket::add_order_to_queue(Order& order) { + if (state == Socket::SocketState::CONNECTED) { + return false; + } if (order.get_size() == 0) { - std::cout << "Socket: Error: order empty\n"; - return false; + LOG_ERROR("Order is empty"); + return false; } { - std::lock_guard lock(mutex); - tx_packet_buffer.push(&order); + std::lock_guard lock(mutex); + tx_packet_buffer.push(move(&order)); } - return true; + return true; } -bool Socket::is_connected(){ - return state == Socket::SocketState::CONNECTED; -} - - +bool Socket::is_connected() { return state == Socket::SocketState::CONNECTED; } diff --git a/Src/HALALMock/Services/Communication/Ethernet/UDP/DatagramSocket.cpp b/Src/HALALMock/Services/Communication/Ethernet/UDP/DatagramSocket.cpp index d573318b9..eda669ba3 100644 --- a/Src/HALALMock/Services/Communication/Ethernet/UDP/DatagramSocket.cpp +++ b/Src/HALALMock/Services/Communication/Ethernet/UDP/DatagramSocket.cpp @@ -1,97 +1,162 @@ - #include "HALALMock/Services/Communication/Ethernet/UDP/DatagramSocket.hpp" + +#include "HALALMock/Services/Logger/Logger.hpp" #define MAX_SIZE_PACKET 1024 DatagramSocket::DatagramSocket() = default; -DatagramSocket::DatagramSocket(DatagramSocket&& other):udp_socket(move(other.udp_socket)), local_ip(move(other.local_ip)) , local_port(move(other.local_port)) ,remote_ip(move(other.remote_ip)), - remote_port(move(other.remote_port)) - {} +DatagramSocket::DatagramSocket(DatagramSocket&& other) + : udp_socket(move(other.udp_socket)), + local_ip(move(other.local_ip)), + local_port(move(other.local_port)), + remote_ip(move(other.remote_ip)), + remote_port(move(other.remote_port)) {} -DatagramSocket::DatagramSocket(IPV4 local_ip, uint32_t local_port, IPV4 remote_ip, uint32_t remote_port): local_ip(local_ip), -local_port(local_port), remote_ip(remote_ip), remote_port(remote_port){ - if(not Ethernet::is_running) { - std::cout<<"Cannot declare UDP socket before Ethernet::start()\n"; - return; - } - create_udp_socket(); - } +DatagramSocket::DatagramSocket(IPV4 local_ip, uint32_t local_port, + IPV4 remote_ip, uint32_t remote_port) + : local_ip(local_ip), + local_port(local_port), + remote_ip(remote_ip), + remote_port(remote_port) { + if (not Ethernet::is_running) { + LOG_ERROR("Unable to declare UDP socket before Ethernet::start()"); + return; + } + create_udp_socket(); +} -DatagramSocket::DatagramSocket(EthernetNode local_node, EthernetNode remote_node): DatagramSocket(local_node.ip, local_node.port, remote_node.ip, remote_node.port){} +DatagramSocket::DatagramSocket(EthernetNode local_node, + EthernetNode remote_node) + : DatagramSocket(local_node.ip, local_node.port, remote_node.ip, + remote_node.port) {} -DatagramSocket::~DatagramSocket(){ - if(not is_disconnected) - close(); +DatagramSocket::~DatagramSocket() { + if (not is_disconnected) close(); } -void DatagramSocket::create_udp_socket(){ - udp_socket = socket(AF_INET,SOCK_DGRAM,0); - if(udp_socket < 0){ - std::cout<<"Socket creation failed\n"; - } - struct sockaddr_in servaddr; - servaddr.sin_family = AF_INET; - servaddr.sin_port = htons(local_port); - servaddr.sin_addr.s_addr = local_ip.address; - if(bind(udp_socket, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){ - std::cout<<"Bind error\n"; - ::close(udp_socket); - is_disconnected = true; - return; - } - is_disconnected = false; - //receiving callback - receiving_udp_thread = std::jthread([&](){ - is_receiving = true; - while(true){ - - uint8_t received_data[1024]; - struct sockaddr_in src_addr; - socklen_t addr_len = sizeof(src_addr); - ssize_t size = recvfrom(udp_socket,(uint8_t*)received_data,MAX_SIZE_PACKET,0,(struct sockaddr *)&src_addr, &addr_len); - if(size < 0){ - if (errno == EBADF){ - std::cout<< "The udp_socket has been close\n"; - break; - } - else{ - std::cout<< "Error in function recvfrom\n"; - continue; - } - } - //receive callback - Packet::parse_data(received_data); - } - is_receiving = false; - - }); - Ethernet::update(); +void DatagramSocket::create_udp_socket() { + udp_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (udp_socket < 0) { + LOG_ERROR("Unable to create socket"); + } + struct sockaddr_in servaddr; + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(local_port); + servaddr.sin_addr.s_addr = local_ip.address; + if (bind(udp_socket, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { + LOG_ERROR("Unable to bind"); + ::close(udp_socket); + is_disconnected = true; + return; + } + is_disconnected = false; + // receiving callback + receiving_udp_thread = std::jthread([&]() { + is_receiving = true; + while (true) { + uint8_t received_data[1024]; + struct sockaddr_in src_addr; + socklen_t addr_len = sizeof(src_addr); + ssize_t size = + recvfrom(udp_socket, (uint8_t*)received_data, MAX_SIZE_PACKET, + 0, (struct sockaddr*)&src_addr, &addr_len); + if (size < 0) { + if (errno == EBADF) { + LOG_WARNING("UDP socket has been closed"); + break; + } else { + LOG_ERROR("Error while receiving data"); + continue; + } + } + // receive callback + Packet::parse_data(received_data); + } + is_receiving = false; + }); + Ethernet::update(); } -void DatagramSocket::operator=(DatagramSocket&& other){ - udp_socket = move(other.udp_socket); - local_ip = move(other.local_ip); - local_port = move(other.local_port); - remote_ip = other.remote_ip; - remote_port = other.remote_port; - other.is_disconnected = true; +void DatagramSocket::operator=(DatagramSocket&& other) { + udp_socket = move(other.udp_socket); + local_ip = move(other.local_ip); + local_port = move(other.local_port); + remote_ip = other.remote_ip; + remote_port = other.remote_port; + other.is_disconnected = true; } -void DatagramSocket::reconnect(){ - is_disconnected = true; - close(); - create_udp_socket(); -} +DatagramSocket::DatagramSocket(EthernetNode local_node, + EthernetNode remote_node) + : DatagramSocket(local_node.ip, local_node.port, remote_node.ip, + remote_node.port) {} -void DatagramSocket::close(){ - if (!is_disconnected){ - if(::close(udp_socket)){ - std::cout<<"Error closing the udp_socket\n"; - } - if(is_receiving){ - receiving_udp_thread.request_stop(); - receiving_udp_thread.~jthread(); - } - is_disconnected = true; - } +DatagramSocket::~DatagramSocket() { + if (not is_disconnected) close(); +} +void DatagramSocket::create_udp_socket() { + udp_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (udp_socket < 0) { + LOG_ERROR("Unable to create socket"); + } + struct sockaddr_in servaddr; + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(local_port); + servaddr.sin_addr.s_addr = local_ip.address; + if (bind(udp_socket, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { + LOG_ERROR(std::format("Unable to bind to address {} in port {}", + local_ip->string_address, local_port)); + close(udp_socket); + is_disconnected = true; + return; + } + is_disconnected = false; + // receiving callback + receiving_udp_thread = std::jthread([&]() { + is_receiving = true; + while (true) { + uint8_t received_data[1024]; + struct sockaddr_in src_addr; + socklen_t addr_len = sizeof(src_addr); + ssize_t size = + recvfrom(udp_socket, (uint8_t*)received_data, MAX_SIZE_PACKET, + 0, (struct sockaddr*)&src_addr, &addr_len); + if (size < 0) { + LOG_ERROR("Unable to receive data"); + is_receiving = false; + return; + } + // receive callback + Packet::parse_data(received_data); + } + }); + Ethernet::update(); +} +void DatagramSocket::operator=(DatagramSocket&& other) { + udp_socket = move(other.udp_socket); + local_ip = move(other.local_ip); + local_port = move(other.local_port); + remote_ip = other.remote_ip; + remote_port = other.remote_port; + other.is_disconnected = true; } +void DatagramSocket::close() { + if (!is_disconnected) { + if (::close(udp_socket)) { + LOG_ERROR("Unable to close UDP socket"); + } + if (is_receiving) { + receiving_udp_thread.request_stop(); + receiving_udp_thread.~jthread(); + } + is_disconnected = true; + } +} +void DatagramSocket::close() { + // check if receiving thread is on and delete it + if (is_receiving) { + receiving_udp_thread.~jthread(); + } + ::close(udp_socket); + is_disconnected = true; +} diff --git a/Src/HALALMock/Services/SharedMemory/SharedMemory.cpp b/Src/HALALMock/Services/SharedMemory/SharedMemory.cpp index 24a4eb7f5..6a4ded656 100644 --- a/Src/HALALMock/Services/SharedMemory/SharedMemory.cpp +++ b/Src/HALALMock/Services/SharedMemory/SharedMemory.cpp @@ -1,14 +1,17 @@ #include "HALALMock/Services/SharedMemory/SharedMemory.hpp" -//includes to create the shared Memory in Posix + +#include "HALALMock/Services/Logger/Logger.hpp" +// includes to create the shared Memory in Posix #include +#include #include #include -#include #include + #include // initialize the static variables -EmulatedPin *SharedMemory::gpio_memory{}; +EmulatedPin* SharedMemory::gpio_memory{}; uint8_t* SharedMemory::state_machine_memory = {}; char* SharedMemory::gpio_memory_name = {}; char* SharedMemory::state_machine_memory_name = {}; @@ -16,136 +19,144 @@ uint8_t* SharedMemory::state_machine_count{}; int SharedMemory::shm_gpio_fd{}; int SharedMemory::shm_state_machine_fd{}; - void SharedMemory::start() { - SharedMemory::gpio_memory_name = const_cast(SHM::gpio_memory_name); - SharedMemory::state_machine_memory_name = const_cast(SHM::state_machine_memory_name); - start_state_machine_memory(); // initialize the state machine shared memory - start_gpio_shared_memory(); // initialize the gpio_shared_memory + SharedMemory::gpio_memory_name = const_cast(SHM::gpio_memory_name); + SharedMemory::state_machine_memory_name = + const_cast(SHM::state_machine_memory_name); + start_state_machine_memory(); // initialize the state machine shared memory + start_gpio_shared_memory(); // initialize the gpio_shared_memory } -void SharedMemory::start(const char* gpio_memory_name, const char* state_machine_memory_name) { - SharedMemory::gpio_memory_name=const_cast(gpio_memory_name); - SharedMemory::state_machine_memory_name=const_cast(state_machine_memory_name); - start_state_machine_memory(); // initialize the state machine shared memory - start_gpio_shared_memory(); // initialize the gpio_shared_memory +void SharedMemory::start(const char* gpio_memory_name, + const char* state_machine_memory_name) { + SharedMemory::gpio_memory_name = const_cast(gpio_memory_name); + SharedMemory::state_machine_memory_name = + const_cast(state_machine_memory_name); + start_state_machine_memory(); // initialize the state machine shared memory + start_gpio_shared_memory(); // initialize the gpio_shared_memory } -void SharedMemory::start_gpio_shared_memory(){ - - //create shared memory object - shm_gpio_fd = shm_open(gpio_memory_name, O_CREAT | O_RDWR,0660); - if(shm_gpio_fd == -1){ - std::cout<<"Error to Open de Shared Memory"; - return; - } - //configure the size of the shared memory object - if(ftruncate(shm_gpio_fd,gpio_memory_size) == -1){ - std::cout<<"Error to asssign memory to the Shared Memory"; - ::close(shm_gpio_fd); - return; - } - //point gpio_memory to the beginning of shared_memory - gpio_memory = static_cast(mmap(0, gpio_memory_size, PROT_WRITE | PROT_READ, MAP_SHARED, shm_gpio_fd, 0)); - if(gpio_memory == MAP_FAILED){ - std::cout<<"Error mapping Shared Memory"; - ::close(shm_gpio_fd); // Close the descriptor if there is a problem with the mapping +void SharedMemory::start_gpio_shared_memory() { + // create shared memory object + shm_gpio_fd = shm_open(gpio_memory_name, O_CREAT | O_RDWR, 0660); + if (shm_gpio_fd == -1) { + LOG_ERROR("Unable to open Shared Memory"); + return; + } + // configure the size of the shared memory object + if (ftruncate(shm_gpio_fd, gpio_memory_size) == -1) { + LOG_ERROR("Unable to assign memory to Shared Memory"); + ::close(shm_gpio_fd); + return; + } + // point gpio_memory to the beginning of shared_memory + gpio_memory = static_cast(mmap(0, gpio_memory_size, + PROT_WRITE | PROT_READ, + MAP_SHARED, shm_gpio_fd, 0)); + if (gpio_memory == MAP_FAILED) { + LOG_ERROR("Unable to map Shared Memory"); + ::close(shm_gpio_fd); // Close the descriptor if there is a problem + // with the mapping return; - } - - // clean the shared memory in case it has info from the previous execution - memset(static_cast(gpio_memory),0,gpio_memory_size); + } + + // clean the shared memory in case it has info from the previous execution + memset(static_cast(gpio_memory), 0, gpio_memory_size); } -void SharedMemory::start_state_machine_memory(){ - - // create the shared memory object - shm_state_machine_fd=shm_open(state_machine_memory_name,O_CREAT | O_RDWR, 0660); - if(shm_state_machine_fd==-1){ - std::cout<<"Error creating the shared memory object\n"; - std::terminate(); - } - // configure the size of the shared memory object - if(ftruncate(shm_state_machine_fd,state_machine_memory_size)==-1){ - std::cout<<"Error configuring the size of the shared memory object\n"; - ::close(shm_state_machine_fd); - std::terminate(); - } - // memory map the shared memory object - state_machine_memory=static_cast(mmap(NULL,state_machine_memory_size,PROT_WRITE | PROT_READ,MAP_SHARED,shm_state_machine_fd,0)); - if(state_machine_memory==MAP_FAILED){ - std::cout<<"Error mapping the shared memory object\n"; - ::close(shm_state_machine_fd); - std::terminate(); - } - - state_machine_count=&state_machine_memory[0]; - *state_machine_count=0; - - // clean the shared memory in case it has info from the previous execution - memset(static_cast(state_machine_memory),0,state_machine_memory_size); +void SharedMemory::start_state_machine_memory() { + // create the shared memory object + shm_state_machine_fd = + shm_open(state_machine_memory_name, O_CREAT | O_RDWR, 0660); + if (shm_state_machine_fd == -1) { + LOG_ERROR("Unable to create the Shared Memory object"); + std::terminate(); + } + // configure the size of the shared memory object + if (ftruncate(shm_state_machine_fd, state_machine_memory_size) == -1) { + LOG_ERROR("Unable to configure the size of the Shared Memory object"); + ::close(shm_state_machine_fd); + std::terminate(); + } + // memory map the shared memory object + state_machine_memory = static_cast( + mmap(NULL, state_machine_memory_size, PROT_WRITE | PROT_READ, + MAP_SHARED, shm_state_machine_fd, 0)); + if (state_machine_memory == MAP_FAILED) { + LOG_ERROR("Unable to map the Shared Memory object"); + ::close(shm_state_machine_fd); + std::terminate(); + } + + state_machine_count = &state_machine_memory[0]; + *state_machine_count = 0; + + // clean the shared memory in case it has info from the previous execution + memset(static_cast(state_machine_memory), 0, + state_machine_memory_size); } -void SharedMemory::close(){ - close_gpio_shared_memory(); - close_state_machine_memory(); +void SharedMemory::close() { + close_gpio_shared_memory(); + close_state_machine_memory(); } -void SharedMemory::close_gpio_shared_memory(){ - if (gpio_memory != nullptr){ - //unmap shared memory - if(munmap(gpio_memory,gpio_memory_size) == -1){ - std::cout<<"Error unmapping the gpio shared_memory\n"; - std::terminate(); - } - //put the pointer to null - gpio_memory = nullptr; - } - int delete_shared_gpio_memory = shm_unlink(gpio_memory_name); - if(delete_shared_gpio_memory == -1){ - std::cout<<"Error unlinking the shared memory object\n"; - std::terminate(); - } - if(shm_gpio_fd!=-1 && ::close(shm_gpio_fd) == -1){ - std::cout<<"Error closing the file descriptor\n"; - std::terminate(); - } +void SharedMemory::close_gpio_shared_memory() { + if (gpio_memory != nullptr) { + // unmap shared memory + if (munmap(gpio_memory, gpio_memory_size) == -1) { + std::cout << "Error unmapping the gpio shared_memory\n"; + LOG_ERROR("Unable to unmap the gpio shared_memory"); + std::terminate(); + } + // put the pointer to null + gpio_memory = nullptr; + } + int delete_shared_gpio_memory = shm_unlink(gpio_memory_name); + if (delete_shared_gpio_memory == -1) { + LOG_ERROR("Unable to unlink the Shared Memory object"); + std::terminate(); + } + if (shm_gpio_fd != -1 && ::close(shm_gpio_fd) == -1) { + LOG_ERROR("Unable to close the file descriptor"); + std::terminate(); + } } -void SharedMemory::close_state_machine_memory(){ - if (state_machine_memory!=nullptr){ - // unmap the shared memory object - if(munmap(state_machine_memory,state_machine_memory_size)==-1){ - std::cout<<"Error unmapping the shared memory object\n"; - std::terminate(); - } - - // point the shared memory object to NULL - state_machine_memory=nullptr; - } - - if(shm_unlink(state_machine_memory_name)==-1){ - std::cout<<"Error unlinking the shared memory object\n"; - std::terminate(); - } - - if(shm_state_machine_fd !=-1 && ::close(shm_state_machine_fd)==-1){ - std::cout<<"Error closing the shared memory file descriptor\n"; - - std::terminate(); - } +void SharedMemory::close_state_machine_memory() { + if (state_machine_memory != nullptr) { + // unmap the shared memory object + if (munmap(state_machine_memory, state_machine_memory_size) == -1) { + LOG_ERROR("Unable to unmap the Shared Memory object"); + std::terminate(); + } + + // point the shared memory object to NULL + state_machine_memory = nullptr; + } + + if (shm_unlink(state_machine_memory_name) == -1) { + LOG_ERROR("Unable to unlink the Shared Memory object"); + std::terminate(); + } + + if (shm_state_machine_fd != -1 && ::close(shm_state_machine_fd) == -1) { + LOG_ERROR("Unable to close the Shared Memory file descriptor"); + + std::terminate(); + } } -void SharedMemory::update_current_state(uint8_t index, uint8_t state){ - state_machine_memory[index]=state; +void SharedMemory::update_current_state(uint8_t index, uint8_t state) { + state_machine_memory[index] = state; } -EmulatedPin& SharedMemory::get_pin(Pin pin){ +EmulatedPin& SharedMemory::get_pin(Pin pin) { auto it = SHM::pin_offsets.find(pin); - if(it == SHM::pin_offsets.end()){ - std::cout<<"Error: Pin " << pin.to_string() << " doesn't exist.\n"; + if (it == SHM::pin_offsets.end()) { + LOG_ERROR(std::format("Pin {} does not exist", pin.to_string())); std::terminate(); } size_t offset = it->second; - if (offset >= gpio_memory_size){ - std::cout<<"Error: Offset " << offset << " is out of scope\n"; + if (offset >= gpio_memory_size) { + LOG_ERROR(std::format("Offset {} is out of scope", offset)); std::terminate(); }