From 717cd0116871625b06af92a35ed71776caa540e8 Mon Sep 17 00:00:00 2001 From: Antoine Date: Tue, 20 Aug 2024 11:50:21 +0200 Subject: [PATCH 1/3] Refactor socket creation to support IPv6 --- src/monitoring.c | 150 ++++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/src/monitoring.c b/src/monitoring.c index 1785471..415f5ed 100644 --- a/src/monitoring.c +++ b/src/monitoring.c @@ -19,6 +19,11 @@ #include #include #include +#include + +#include +#include +#include #include #include "eeprom_config.h" @@ -91,51 +96,65 @@ static void * monitoring_thread(void * p_data); /** * @brief Create, bind and listen socket * - * Will use TCP over IPv4 - * @param address address to bind to - * @param portnum port to bind to + * Will use TCP over IP + * @param address address to listen from. It can be NULL to mean any address. + * @param port port to bind to, it can be a number or the name of a service * @return socket fd on success, -1 if error */ -static int listen_inet_socket(const char* address, unsigned short portnum) { - if (!address) { - log_error("Monitoring address (provided address is NULL)"); +static int create_socket(const char* address, const char* port) +{ + int status; + int socket_fd; + const bool reuse_address = true; + struct addrinfo* addresses = NULL; + struct addrinfo* current; + struct addrinfo hint = { + .ai_family = AF_UNSPEC, + .ai_protocol = IPPROTO_TCP, + .ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_CANONNAME + }; + + status = getaddrinfo(address, port, &hint, &addresses); + if (status == EAI_SYSTEM) + { + log_error("Unable to translate '%s:%s' into an Internet adrress: %s", address, port, strerror(errno)); return -1; } - - int sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd < 0) { - log_error("opening socket"); + else if (status != 0) + { + log_error("Unable to translate '%s:%s' into an Internet adrress: %s", address, port, gai_strerror(status)); return -1; } - // This helps avoid spurious EADDRINUSE when the previous instance of this - // server died. - int opt = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { - log_error("setsockopt"); - close(sockfd); - return -1; - } + for (current = addresses; current; current = current->ai_next) + { + socket_fd = socket(current->ai_family, current->ai_socktype, current->ai_protocol); + if (socket_fd < 0) + { + log_warn("Couldn't open a socket for '%s': %s", current->ai_canonname, strerror(errno)); + continue; + } - struct sockaddr_in serv_addr; - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = inet_addr(address); - serv_addr.sin_port = htons(portnum); + if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(reuse_address)) < 0) + log_warn("Unable to configure the socket for '%s': %s", current->ai_canonname, strerror(errno)); + else if (bind(socket_fd, current->ai_addr, current->ai_addrlen) < 0) + log_warn("Couldn't bind to '%s': %s", current->ai_canonname, strerror(errno)); + else if (listen(socket_fd, N_BACKLOG) < 0) + log_warn("Couldn't listen for connections on '%s': %s", current->ai_canonname, strerror(errno)); + else + break; - if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { - log_error("on binding"); - close(sockfd); - return -1; + close(socket_fd); } + freeaddrinfo(addresses); - if (listen(sockfd, N_BACKLOG) < 0) { - log_error("on listen"); - close(sockfd); + if (current == NULL) + { + log_error("Could not bind / configure / listen to any address matching %s:%s", address, port); return -1; } - - return sockfd; + log_info("Listening on %s", current->ai_canonname); + return socket_fd; } /** @@ -145,33 +164,18 @@ static int listen_inet_socket(const char* address, unsigned short portnum) { */ static void make_socket_non_blocking(int sockfd) { int flags = fcntl(sockfd, F_GETFL, 0); - if (flags == -1) { - log_error("fcntl F_GETFL"); + if (flags == -1) + { + log_error("Unable to get file status flags of socket: %s", strerror(errno)); } - if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) { - log_error("fcntl F_SETFL O_NONBLOCK"); + if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1) + { + log_error("Unable to set file status flags of socker: %s", strerror(errno)); } return; } -/** - * @brief Indicate a peer is connected - * - * @param sa socket address and port - * @param salen socket name length - */ -static void report_peer_connected(const struct sockaddr_in* sa, socklen_t salen) { - char hostbuf[NI_MAXHOST]; - char portbuf[NI_MAXSERV]; - if (getnameinfo((struct sockaddr*)sa, salen, hostbuf, NI_MAXHOST, portbuf, - NI_MAXSERV, 0) == 0) { - log_debug("peer (%s, %s) connected", hostbuf, portbuf); - } else { - log_debug("peer (unknown) connected"); - } -} - /** * @brief Initialize receive buffer once peer is connected * @@ -668,33 +672,30 @@ static fd_status_t on_peer_ready_send(int sockfd, struct monitoring * monitoring */ struct monitoring* monitoring_init(const struct config *config, struct devices_path *devices_path) { - int port; - int ret; - struct monitoring *monitoring; + int ret; + struct monitoring* monitoring; + const char* address; + const char* port; - const char *address = config_get(config, "socket-address"); - if (address == NULL) { - log_error("Monitoring: socket-address not defined in config %s", config->path); + if (devices_path == NULL) { + log_error("No struct devices path passed !"); return NULL; } - port = config_get_unsigned_number(config, "socket-port"); - if (port < 0) { - log_error( - "Monitoring: Error %d fetching socket-port from config %s", - port, - config->path - ); - return NULL; - } + address = config_get(config, "socket-address"); + if (address == NULL) + log_warn("Monitoring: socket-address not defined in config %s, wildcard address will be used", config->path); - if (devices_path == NULL) { - log_error("No struct devices path passed !"); + port = config_get(config, "socket-port"); + if (port == NULL) + { + log_error("Monitoring: socket-port not found in config %s", config->path); return NULL; } - monitoring = (struct monitoring *) malloc(sizeof(struct monitoring)); - if (monitoring == NULL) { + monitoring = (struct monitoring*)malloc(sizeof(struct monitoring)); + if (monitoring == NULL) + { log_error("Monitoring: Could not allocate memory for monitoring struct"); return NULL; } @@ -739,8 +740,9 @@ struct monitoring* monitoring_init(const struct config *config, struct devices_p pthread_mutex_init(&monitoring->mutex, NULL); pthread_cond_init(&monitoring->cond, NULL); - monitoring->sockfd = listen_inet_socket(address, port); - if (monitoring->sockfd == -1) { + monitoring->sockfd = create_socket(address, port); + if (monitoring->sockfd == -1) + { log_error("Monitoring: Error creating monitoring socket"); free(monitoring); return NULL; From f6aa22ae33f42e09faa5c117cf628520f5d65dad Mon Sep 17 00:00:00 2001 From: Antoine Date: Tue, 20 Aug 2024 18:50:17 +0200 Subject: [PATCH 2/3] Refactor client util to support IPv6 --- utils/art_monitoring_client.c | 85 ++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/utils/art_monitoring_client.c b/utils/art_monitoring_client.c index 08089cf..6edaf90 100644 --- a/utils/art_monitoring_client.c +++ b/utils/art_monitoring_client.c @@ -19,14 +19,16 @@ #include #include #include +#include +#include #include "log.h" #include "monitoring.h" static void print_help(void) { - printf("usage: art_monitoring_client [-h -r REQUEST_TYPE] -a ADDRESS -p PORT\n"); - printf("- -a ADDRESS: Address socket should bind to\n"); + printf("usage: art_monitoring_client [-h -r REQUEST_TYPE -a ADDRESS] -p PORT\n"); + printf("- -a ADDRESS: Address socket should bind to. Defaults to local address\n"); printf("- -p PORT: Port socket should bind to\n"); printf("- -r REQUEST_TYPE: send a request to oscillatord. Accepted values are:\n"); printf("\t- calibration: request a calibration of the algorithm\n"); @@ -74,8 +76,8 @@ static struct json_object *json_send_and_receive(int sockfd, int request) int main(int argc, char *argv[]) { int c; int request = REQUEST_NONE; - int socket_port = -1; - char *socket_addr = NULL; + const char* socket_port = NULL; + const char* socket_addr = NULL; while ((c = getopt(argc, argv, "a:p:r:h")) != -1) switch (c) @@ -84,7 +86,7 @@ int main(int argc, char *argv[]) { socket_addr = optarg; break; case 'p': - socket_port = atoi(optarg); + socket_port = optarg; break; case 'r': if (strcmp(optarg, "calibration") == 0) @@ -127,49 +129,68 @@ int main(int argc, char *argv[]) { fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); - return -1; + return EXIT_FAILURE; default: abort(); } - if (socket_addr == NULL || socket_port <= 0) { - log_error("Bad address / port"); + if (socket_port == NULL) { + log_error("Bad port"); print_help(); - return -1; + return EXIT_FAILURE; } - int sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd == -1) + int socket_fd; + int status; + struct addrinfo* addresses; + struct addrinfo* current; + struct addrinfo hint = { + .ai_family = AF_UNSPEC, + .ai_protocol = IPPROTO_TCP, + }; + + status = getaddrinfo(socket_addr, socket_port, &hint, &addresses); + if (status == EAI_SYSTEM) { - log_error("Could not connect to socket !"); - log_error("Try running with sudo"); - log_error("FAIL"); - return -1; + log_error("Unable to get an Internet address from '%s:%s': %s", socket_addr, socket_port, strerror(errno)); + return EXIT_FAILURE; + } + else if (status != 0) + { + log_error("Unable to get an Internet address from '%s:%s': %s", socket_addr, socket_port, gai_strerror(status)); + return EXIT_FAILURE; } - struct sockaddr_in server_addr; - memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(socket_port); - server_addr.sin_addr.s_addr = inet_addr(socket_addr); + for (current = addresses; current; current = current->ai_next) + { + socket_fd = socket(current->ai_family, current->ai_socktype, current->ai_protocol); + if (socket_fd < 0) + { + log_warn("Couldn't open a socket for '%s:%s' (IPv%i): %s", socket_addr, socket_port, current->ai_family == AF_INET ? 4 : 6, strerror(errno)); + continue; + } + if (connect(socket_fd, current->ai_addr, current->ai_addrlen) == 0) + break; + log_warn("Couldn't connect to '%s:%s' (IPv%i) : %s", socket_addr, socket_port, current->ai_family == AF_INET ? 4 : 6, strerror(errno)); + + close(socket_fd); + } + freeaddrinfo(addresses); - /* Initiate a connection to the server */ - int ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); - if (ret == -1) + if (current == NULL) { - log_error("Could not connect to socket !"); - log_error("FAIL"); - return -1; + log_error("Could not connect to %s:%s", socket_addr, socket_port); + return EXIT_FAILURE; } /* Request data through socket */ - struct json_object *obj = json_send_and_receive(sockfd, request); + struct json_object *obj = json_send_and_receive(socket_fd, request); struct json_object *layer_1; struct json_object *layer_2; struct json_object *layer_3; log_info(json_object_to_json_string(obj)); - + /* Disciplining */ json_object_object_get_ex(obj, "disciplining", &layer_1); if (layer_1 != NULL) { @@ -310,7 +331,7 @@ int main(int argc, char *argv[]) { log_info("\t\t- %s: %s", temperature_range, json_object_get_string(mean_value)); } } - + } /* ACTION */ @@ -320,9 +341,9 @@ int main(int argc, char *argv[]) { free(obj); - close(sockfd); + close(socket_fd); log_info("PASSED !"); - - return 0; + + return EXIT_SUCCESS; } From 3bd60f25fbcae3bcc95d69e710c5c67bc519b887 Mon Sep 17 00:00:00 2001 From: Antoine Date: Tue, 20 Aug 2024 20:46:48 +0200 Subject: [PATCH 3/3] Fix addrinfo flags --- src/monitoring.c | 27 ++++++++++++++------------- utils/art_monitoring_client.c | 20 +++++++++++--------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/monitoring.c b/src/monitoring.c index 415f5ed..5f96831 100644 --- a/src/monitoring.c +++ b/src/monitoring.c @@ -105,13 +105,13 @@ static int create_socket(const char* address, const char* port) { int status; int socket_fd; - const bool reuse_address = true; + const int reuse_address = true; struct addrinfo* addresses = NULL; struct addrinfo* current; struct addrinfo hint = { .ai_family = AF_UNSPEC, .ai_protocol = IPPROTO_TCP, - .ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_CANONNAME + .ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_ADDRCONFIG }; status = getaddrinfo(address, port, &hint, &addresses); @@ -129,18 +129,23 @@ static int create_socket(const char* address, const char* port) for (current = addresses; current; current = current->ai_next) { socket_fd = socket(current->ai_family, current->ai_socktype, current->ai_protocol); + if (socket_fd < 0) { - log_warn("Couldn't open a socket for '%s': %s", current->ai_canonname, strerror(errno)); + log_warn("Couldn't open a socket for IPv%c, %s, %s: %s", + current->ai_family == AF_INET ? '4' : '6', + current->ai_socktype == SOCK_STREAM ? "Stream" : "Datagram", + current->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP", + strerror(errno)); continue; } if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_address, sizeof(reuse_address)) < 0) - log_warn("Unable to configure the socket for '%s': %s", current->ai_canonname, strerror(errno)); + log_warn("Unable to configure socket: %s", strerror(errno)); else if (bind(socket_fd, current->ai_addr, current->ai_addrlen) < 0) - log_warn("Couldn't bind to '%s': %s", current->ai_canonname, strerror(errno)); + log_warn("Couldn't bind socket to %s: %s", address, strerror(errno)); else if (listen(socket_fd, N_BACKLOG) < 0) - log_warn("Couldn't listen for connections on '%s': %s", current->ai_canonname, strerror(errno)); + log_warn("Couldn't listen for connections on %s: %s", address, strerror(errno)); else break; @@ -153,7 +158,6 @@ static int create_socket(const char* address, const char* port) log_error("Could not bind / configure / listen to any address matching %s:%s", address, port); return -1; } - log_info("Listening on %s", current->ai_canonname); return socket_fd; } @@ -756,12 +760,9 @@ struct monitoring* monitoring_init(const struct config *config, struct devices_p monitoring ); - log_info( - "Monitoring: INITIALIZATION: Successfully started monitoring thread, listening on %s:%d", - address, - port - ); - if (ret != 0) { + log_info("Monitoring: INITIALIZATION: Successfully started monitoring thread, listening on %s:%s", address, port); + if (ret != 0) + { log_error("Monitoring: Error creating monitoring thread: %d", ret); close(monitoring->sockfd); free(monitoring); diff --git a/utils/art_monitoring_client.c b/utils/art_monitoring_client.c index 6edaf90..2f7cfb2 100644 --- a/utils/art_monitoring_client.c +++ b/utils/art_monitoring_client.c @@ -8,22 +8,24 @@ * @copyright Copyright (c) 2022 * */ -#include -#include +#include "log.h" +#include "monitoring.h" + #include #include +#include + +#include #include +#include +#include + +#include +#include #include #include #include -#include -#include #include -#include -#include - -#include "log.h" -#include "monitoring.h" static void print_help(void) {