From 0294f3d8d3d86ca78b13d822a878a89ddd9fb23f Mon Sep 17 00:00:00 2001 From: Aemiii91 <44569252+Aemiii91@users.noreply.github.com> Date: Sun, 29 Dec 2024 01:06:36 +0100 Subject: [PATCH 1/4] Improve RetroArch UDP command util --- src/common/utils/udp.c | 114 ++++++++++++++++++++++++++++++++++ src/common/utils/udp.h | 24 +++++++ src/keymon/Makefile | 3 + src/keymon/menuButtonAction.h | 5 +- src/sendUDP/Makefile | 3 + src/sendUDP/sendUDP.c | 74 ++++++++++++---------- 6 files changed, 188 insertions(+), 35 deletions(-) create mode 100644 src/common/utils/udp.c create mode 100644 src/common/utils/udp.h diff --git a/src/common/utils/udp.c b/src/common/utils/udp.c new file mode 100644 index 0000000000..919c22066e --- /dev/null +++ b/src/common/utils/udp.c @@ -0,0 +1,114 @@ +#include "udp.h" + +#include +#include +#include + +static const char *UDP_DEFAULT_IP = "127.0.0.1"; // localhost +static const int UDP_DEFAULT_PORT = 55355; // default RetroArch CMD port + +static int _init_socket(const char *ipAddress, int port, int *socket_fd, struct sockaddr_in *server_address) +{ + *socket_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (*socket_fd == -1) { + perror("Socket creation failed"); + return -1; + } + + memset(server_address, 0, sizeof(*server_address)); + server_address->sin_family = AF_INET; + server_address->sin_port = htons(port); + if (inet_pton(AF_INET, ipAddress, &server_address->sin_addr) <= 0) { + perror("Invalid IP address"); + close(*socket_fd); + return -1; + } + + return 0; +} + +int udp_send(const char *ipAddress, int port, const char *message) +{ + int socket_fd; + struct sockaddr_in server_address; + + if (_init_socket(ipAddress, port, &socket_fd, &server_address) == -1) { + return -1; + } + + if (sendto(socket_fd, message, strlen(message), 0, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) { + perror("Failed to send data"); + close(socket_fd); + return -1; + } + + close(socket_fd); + return 0; +} + +int udp_send_receive(const char *ipAddress, int port, const char *message, char *response, size_t response_size) +{ + int socket_fd; + struct sockaddr_in server_address; + + if (_init_socket(ipAddress, port, &socket_fd, &server_address) == -1) { + return -1; + } + + if (sendto(socket_fd, message, strlen(message), 0, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) { + perror("Failed to send data"); + close(socket_fd); + return -1; + } + + ssize_t bytes_received = recvfrom(socket_fd, response, response_size, 0, NULL, NULL); + if (bytes_received == -1) { + perror("Failed to receive data"); + close(socket_fd); + return -1; + } + + response[bytes_received] = '\0'; // Null-terminate the received string + + close(socket_fd); + return 0; +} + +int retroarch_cmd(const char *cmd) +{ + return udp_send(UDP_DEFAULT_IP, UDP_DEFAULT_PORT, cmd); +} + +int retroarch_get(const char *cmd, char *response, size_t response_size) +{ + return udp_send_receive(UDP_DEFAULT_IP, UDP_DEFAULT_PORT, cmd, response, response_size); +} + +int retroarch_quit(void) +{ + return retroarch_cmd("QUIT"); +} + +int retroarch_toggleMenu(void) +{ + return retroarch_cmd("MENU_TOGGLE"); +} + +int retroarch_getInfo(RetroArchInfo_t *info) +{ + char response[128]; + if (retroarch_get("GET_INFO", response, sizeof(response)) == -1) { + return -1; + } + + // Parse response "GET_INFO %d %d NO" or "GET_INFO %d %d %d" + int parsed = sscanf(response, "GET_INFO %u %u %d", &info->max_disk_slots, &info->disk_slot, &info->state_slot); + + if (parsed < 2) { + return -1; + } + + info->has_state_slot = parsed == 3; + + return 0; +} diff --git a/src/common/utils/udp.h b/src/common/utils/udp.h new file mode 100644 index 0000000000..5af5cdd272 --- /dev/null +++ b/src/common/utils/udp.h @@ -0,0 +1,24 @@ +#ifndef UTILS_UDP_H__ +#define UTILS_UDP_H__ + +#include +#include + +typedef struct RetroArchInfo { + unsigned int max_disk_slots; + unsigned int disk_slot; + int state_slot; + bool has_state_slot; +} RetroArchInfo_t; + +int udp_send(const char *ipAddress, int port, const char *message); +int udp_send_receive(const char *ipAddress, int port, const char *message, char *response, size_t response_size); + +int retroarch_cmd(const char *cmd); // Send RetroArch UDP command +int retroarch_get(const char *cmd, char *response, size_t response_size); // Get RetroArch UDP command response + +int retroarch_quit(void); // RetroArch QUIT +int retroarch_toggleMenu(void); // RetroArch MENU_TOGGLE +int retroarch_getInfo(RetroArchInfo_t *info); + +#endif // UTILS_UDP_H__ diff --git a/src/keymon/Makefile b/src/keymon/Makefile index 17a8b43058..59a8926838 100644 --- a/src/keymon/Makefile +++ b/src/keymon/Makefile @@ -2,6 +2,9 @@ INCLUDE_SHMVAR=1 INCLUDE_CJSON=1 include ../common/config.mk +CFILES := $(CFILES) \ + ../common/utils/udp.c + TARGET = keymon CFLAGS := $(CFLAGS) -Os -ffunction-sections -fdata-sections LDFLAGS := $(LDFLAGS) -lpthread -lpng -Wl,--gc-sections diff --git a/src/keymon/menuButtonAction.h b/src/keymon/menuButtonAction.h index 50d3f25a91..3e2e20bc42 100644 --- a/src/keymon/menuButtonAction.h +++ b/src/keymon/menuButtonAction.h @@ -15,6 +15,7 @@ #include "../tweaks/tools_defs.h" #include "./input_fd.h" +#include "utils/udp.h" static SystemState menu_last_state = MODE_UNKNOWN; static int menu_last_pressed = 0; @@ -83,7 +84,7 @@ bool terminate_retroarch(void) // send signal kill(pid, SIGCONT); usleep(100000); - system("sendUDP QUIT"); + retroarch_quit(); // wait for terminate sprintf(fname, "/proc/%d", pid); @@ -180,7 +181,7 @@ void action_RA_quickSwitch(void) void action_RA_toggleMenu(void) { - system("sendUDP MENU_TOGGLE"); + retroarch_toggleMenu(); } void action_drastic_gameSwitcher(void) diff --git a/src/sendUDP/Makefile b/src/sendUDP/Makefile index 7ffbd44a43..2dab81ee01 100644 --- a/src/sendUDP/Makefile +++ b/src/sendUDP/Makefile @@ -1,5 +1,8 @@ include ../common/config.mk +CFILES := $(CFILES) \ + ../common/utils/udp.c + TARGET = sendUDP include ../common/commands.mk diff --git a/src/sendUDP/sendUDP.c b/src/sendUDP/sendUDP.c index 59c5f06559..95f9ff2387 100644 --- a/src/sendUDP/sendUDP.c +++ b/src/sendUDP/sendUDP.c @@ -1,55 +1,63 @@ -#include #include #include #include #include +#include "utils/udp.h" + int main(int argc, char *argv[]) { char *ipAddress = "127.0.0.1"; // localhost int port = 55355; // default RetroArch CMD port - char *message; // the message to send + char *message; + size_t response_size = 0; - if (argc < 2) { - fprintf(stderr, "Usage: %s [ ]\n", argv[0]); + if (argc < 2 || (argc == 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0))) { + fprintf(stderr, "Usage: %s [-h ] [-p ] [-r ] \n", argv[0]); exit(EXIT_FAILURE); } - message = argv[1]; - - if (argc == 4) { - ipAddress = argv[2]; - port = atoi(argv[3]); - } - - int socket_fd = socket(AF_INET, SOCK_DGRAM, 0); - if (socket_fd == -1) { - perror("Socket creation failed"); - exit(EXIT_FAILURE); + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-h") == 0) { + if (i + 1 < argc) { + ipAddress = argv[i + 1]; + i++; + } + } + else if (strcmp(argv[i], "-p") == 0) { + if (i + 1 < argc) { + port = atoi(argv[i + 1]); + i++; + } + } + else if (strcmp(argv[i], "-r") == 0) { + if (i + 1 < argc) { + response_size = atoi(argv[i + 1]); + i++; + } + } + else { + message = argv[i]; + } } - struct sockaddr_in server_address; - memset(&server_address, 0, sizeof(server_address)); - server_address.sin_family = AF_INET; - server_address.sin_port = htons(port); - if (inet_pton(AF_INET, ipAddress, &server_address.sin_addr) <= 0) { - perror("Invalid IP address"); - close(socket_fd); - exit(EXIT_FAILURE); - } + if (response_size > 0) { + char *response = (char *)malloc(response_size); + if (response == NULL) { + perror("Failed to allocate memory for response"); + exit(EXIT_FAILURE); + } - ssize_t bytes_sent = sendto(socket_fd, message, strlen(message), 0, - (struct sockaddr *)&server_address, sizeof(server_address)); + if (udp_send_receive(ipAddress, port, message, response, response_size) == -1) { + exit(EXIT_FAILURE); + } - if (bytes_sent == -1) { - perror("Failed to send data"); - close(socket_fd); + printf("%s\n", response); + free(response); + } + else if (udp_send(ipAddress, port, message) == -1) { exit(EXIT_FAILURE); } - printf("Sent %d bytes to %s:%d\n", bytes_sent, ipAddress, port); - - close(socket_fd); - return EXIT_SUCCESS; } From b1160564eb2497d1393bb95b159bb2b919e82080 Mon Sep 17 00:00:00 2001 From: Aemiii91 <44569252+Aemiii91@users.noreply.github.com> Date: Sun, 29 Dec 2024 01:47:36 +0100 Subject: [PATCH 2/4] Rename constants --- src/common/utils/udp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/common/utils/udp.c b/src/common/utils/udp.c index 919c22066e..29c3acb23f 100644 --- a/src/common/utils/udp.c +++ b/src/common/utils/udp.c @@ -4,8 +4,8 @@ #include #include -static const char *UDP_DEFAULT_IP = "127.0.0.1"; // localhost -static const int UDP_DEFAULT_PORT = 55355; // default RetroArch CMD port +static const char *LOCALHOST_IP = "127.0.0.1"; +static const int RETROARCH_CMD_UDP_PORT = 55355; static int _init_socket(const char *ipAddress, int port, int *socket_fd, struct sockaddr_in *server_address) { @@ -76,12 +76,12 @@ int udp_send_receive(const char *ipAddress, int port, const char *message, char int retroarch_cmd(const char *cmd) { - return udp_send(UDP_DEFAULT_IP, UDP_DEFAULT_PORT, cmd); + return udp_send(LOCALHOST_IP, RETROARCH_CMD_UDP_PORT, cmd); } int retroarch_get(const char *cmd, char *response, size_t response_size) { - return udp_send_receive(UDP_DEFAULT_IP, UDP_DEFAULT_PORT, cmd, response, response_size); + return udp_send_receive(LOCALHOST_IP, RETROARCH_CMD_UDP_PORT, cmd, response, response_size); } int retroarch_quit(void) From bc53f6ad16ab1e93a5c5748dbe480a88044a99fa Mon Sep 17 00:00:00 2001 From: Aemiii91 <44569252+Aemiii91@users.noreply.github.com> Date: Sun, 29 Dec 2024 21:48:11 +0100 Subject: [PATCH 3/4] Separate RA commands and UDP code + add retries --- src/common/utils/retroarch_cmd.c | 47 +++++++++++++ src/common/utils/retroarch_cmd.h | 21 ++++++ src/common/utils/udp.c | 116 +++++++++++++++++++++---------- src/common/utils/udp.h | 16 +---- src/keymon/Makefile | 3 +- src/keymon/menuButtonAction.h | 2 +- 6 files changed, 152 insertions(+), 53 deletions(-) create mode 100644 src/common/utils/retroarch_cmd.c create mode 100644 src/common/utils/retroarch_cmd.h diff --git a/src/common/utils/retroarch_cmd.c b/src/common/utils/retroarch_cmd.c new file mode 100644 index 0000000000..34d2bed0bb --- /dev/null +++ b/src/common/utils/retroarch_cmd.c @@ -0,0 +1,47 @@ +#include "retroarch_cmd.h" + +#include + +#include "udp.h" + +static const char *LOCALHOST_IP = "127.0.0.1"; +static const int RETROARCH_CMD_UDP_PORT = 55355; + +int retroarch_cmd(const char *cmd) +{ + return udp_send(LOCALHOST_IP, RETROARCH_CMD_UDP_PORT, cmd); +} + +int retroarch_get(const char *cmd, char *response, size_t response_size) +{ + return udp_send_receive(LOCALHOST_IP, RETROARCH_CMD_UDP_PORT, cmd, response, response_size); +} + +int retroarch_quit(void) +{ + return retroarch_cmd("QUIT"); +} + +int retroarch_toggleMenu(void) +{ + return retroarch_cmd("MENU_TOGGLE"); +} + +int retroarch_getInfo(RetroArchInfo_t *info) +{ + char response[128]; + if (retroarch_get("GET_INFO", response, sizeof(response)) == -1) { + return -1; + } + + // Parse response "GET_INFO %d %d NO" or "GET_INFO %d %d %d" + int parsed = sscanf(response, "GET_INFO %u %u %d", &info->max_disk_slots, &info->disk_slot, &info->state_slot); + + if (parsed < 2) { + return -1; + } + + info->has_state_slot = parsed == 3; + + return 0; +} diff --git a/src/common/utils/retroarch_cmd.h b/src/common/utils/retroarch_cmd.h new file mode 100644 index 0000000000..064a686506 --- /dev/null +++ b/src/common/utils/retroarch_cmd.h @@ -0,0 +1,21 @@ +#ifndef UTILS_RETROARCH_CMD_H__ +#define UTILS_RETROARCH_CMD_H__ + +#include +#include + +typedef struct RetroArchInfo { + unsigned int max_disk_slots; + unsigned int disk_slot; + int state_slot; + bool has_state_slot; +} RetroArchInfo_t; + +int retroarch_cmd(const char *cmd); // Send RetroArch UDP command +int retroarch_get(const char *cmd, char *response, size_t response_size); // Get RetroArch UDP command response + +int retroarch_quit(void); // RetroArch QUIT +int retroarch_toggleMenu(void); // RetroArch MENU_TOGGLE +int retroarch_getInfo(RetroArchInfo_t *info); // Get RetroArch info + +#endif // UTILS_RETROARCH_CMD_H__ \ No newline at end of file diff --git a/src/common/utils/udp.c b/src/common/utils/udp.c index 29c3acb23f..b936e01993 100644 --- a/src/common/utils/udp.c +++ b/src/common/utils/udp.c @@ -1,11 +1,16 @@ #include "udp.h" +#include +#include #include #include +#include #include -static const char *LOCALHOST_IP = "127.0.0.1"; -static const int RETROARCH_CMD_UDP_PORT = 55355; +static const int PING_TIMEOUT_MS = 100; +static const int MAX_RETRIES = 3; +static const int RETRY_DELAY_MS = 500; +static const int RECV_TIMEOUT_MS = 60000; static int _init_socket(const char *ipAddress, int port, int *socket_fd, struct sockaddr_in *server_address) { @@ -27,7 +32,42 @@ static int _init_socket(const char *ipAddress, int port, int *socket_fd, struct return 0; } -int udp_send(const char *ipAddress, int port, const char *message) +static int _ping_socket(int socket_fd, struct sockaddr_in *server_address) +{ + const char *ping_message = "VERSION"; + char response[32]; + struct timeval timeout; + timeout.tv_sec = PING_TIMEOUT_MS / 1000; + timeout.tv_usec = (PING_TIMEOUT_MS % 1000) * 1000; + + // Set receive timeout + if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + perror("Failed to set socket receive timeout"); + return -1; + } + + // Send ping message + if (sendto(socket_fd, ping_message, strlen(ping_message), 0, (struct sockaddr *)server_address, sizeof(*server_address)) == -1) { + perror("Failed to send ping"); + return -1; + } + + // Wait for response + ssize_t bytes_received = recvfrom(socket_fd, response, sizeof(response), 0, NULL, NULL); + if (bytes_received == -1) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + fprintf(stderr, "Ping timeout\n"); + } + else { + perror("Failed to receive ping response"); + } + return -1; + } + + return 0; +} + +static int _udp_send(const char *ipAddress, int port, const char *message) { int socket_fd; struct sockaddr_in server_address; @@ -36,6 +76,11 @@ int udp_send(const char *ipAddress, int port, const char *message) return -1; } + if (_ping_socket(socket_fd, &server_address) == -1) { + close(socket_fd); + return -1; + } + if (sendto(socket_fd, message, strlen(message), 0, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) { perror("Failed to send data"); close(socket_fd); @@ -46,7 +91,7 @@ int udp_send(const char *ipAddress, int port, const char *message) return 0; } -int udp_send_receive(const char *ipAddress, int port, const char *message, char *response, size_t response_size) +static int _udp_send_receive(const char *ipAddress, int port, const char *message, char *response, size_t response_size) { int socket_fd; struct sockaddr_in server_address; @@ -55,12 +100,28 @@ int udp_send_receive(const char *ipAddress, int port, const char *message, char return -1; } + if (_ping_socket(socket_fd, &server_address) == -1) { + close(socket_fd); + return -1; + } + if (sendto(socket_fd, message, strlen(message), 0, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) { perror("Failed to send data"); close(socket_fd); return -1; } + // Set a longer timeout for receiving the response + struct timeval timeout; + timeout.tv_sec = RECV_TIMEOUT_MS / 1000; + timeout.tv_usec = (RECV_TIMEOUT_MS % 1000) * 1000; + + if (setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) { + perror("Failed to set socket receive timeout"); + close(socket_fd); + return -1; + } + ssize_t bytes_received = recvfrom(socket_fd, response, response_size, 0, NULL, NULL); if (bytes_received == -1) { perror("Failed to receive data"); @@ -74,41 +135,24 @@ int udp_send_receive(const char *ipAddress, int port, const char *message, char return 0; } -int retroarch_cmd(const char *cmd) -{ - return udp_send(LOCALHOST_IP, RETROARCH_CMD_UDP_PORT, cmd); -} - -int retroarch_get(const char *cmd, char *response, size_t response_size) -{ - return udp_send_receive(LOCALHOST_IP, RETROARCH_CMD_UDP_PORT, cmd, response, response_size); -} - -int retroarch_quit(void) -{ - return retroarch_cmd("QUIT"); -} - -int retroarch_toggleMenu(void) +int udp_send(const char *ipAddress, int port, const char *message) { - return retroarch_cmd("MENU_TOGGLE"); + for (int attempt = 0; attempt < MAX_RETRIES; attempt++) { + if (_udp_send(ipAddress, port, message) == 0) { + return 0; // Success + } + usleep(RETRY_DELAY_MS * 1000); // Delay before retrying + } + return -1; // Failed after retries } -int retroarch_getInfo(RetroArchInfo_t *info) +int udp_send_receive(const char *ipAddress, int port, const char *message, char *response, size_t response_size) { - char response[128]; - if (retroarch_get("GET_INFO", response, sizeof(response)) == -1) { - return -1; - } - - // Parse response "GET_INFO %d %d NO" or "GET_INFO %d %d %d" - int parsed = sscanf(response, "GET_INFO %u %u %d", &info->max_disk_slots, &info->disk_slot, &info->state_slot); - - if (parsed < 2) { - return -1; + for (int attempt = 0; attempt < MAX_RETRIES; attempt++) { + if (_udp_send_receive(ipAddress, port, message, response, response_size) == 0) { + return 0; // Success + } + usleep(RETRY_DELAY_MS * 1000); // Delay before retrying } - - info->has_state_slot = parsed == 3; - - return 0; + return -1; // Failed after retries } diff --git a/src/common/utils/udp.h b/src/common/utils/udp.h index 5af5cdd272..cfaa4ff481 100644 --- a/src/common/utils/udp.h +++ b/src/common/utils/udp.h @@ -1,24 +1,10 @@ #ifndef UTILS_UDP_H__ #define UTILS_UDP_H__ -#include #include - -typedef struct RetroArchInfo { - unsigned int max_disk_slots; - unsigned int disk_slot; - int state_slot; - bool has_state_slot; -} RetroArchInfo_t; +#include int udp_send(const char *ipAddress, int port, const char *message); int udp_send_receive(const char *ipAddress, int port, const char *message, char *response, size_t response_size); -int retroarch_cmd(const char *cmd); // Send RetroArch UDP command -int retroarch_get(const char *cmd, char *response, size_t response_size); // Get RetroArch UDP command response - -int retroarch_quit(void); // RetroArch QUIT -int retroarch_toggleMenu(void); // RetroArch MENU_TOGGLE -int retroarch_getInfo(RetroArchInfo_t *info); - #endif // UTILS_UDP_H__ diff --git a/src/keymon/Makefile b/src/keymon/Makefile index 59a8926838..c634e70ca9 100644 --- a/src/keymon/Makefile +++ b/src/keymon/Makefile @@ -3,7 +3,8 @@ INCLUDE_CJSON=1 include ../common/config.mk CFILES := $(CFILES) \ - ../common/utils/udp.c + ../common/utils/udp.c \ + ../common/utils/retroarch_cmd.c TARGET = keymon CFLAGS := $(CFLAGS) -Os -ffunction-sections -fdata-sections diff --git a/src/keymon/menuButtonAction.h b/src/keymon/menuButtonAction.h index 3e2e20bc42..0e2da86f45 100644 --- a/src/keymon/menuButtonAction.h +++ b/src/keymon/menuButtonAction.h @@ -15,7 +15,7 @@ #include "../tweaks/tools_defs.h" #include "./input_fd.h" -#include "utils/udp.h" +#include "utils/retroarch_cmd.h" static SystemState menu_last_state = MODE_UNKNOWN; static int menu_last_pressed = 0; From 2c6a8d95506dc66051dd3cb4961365a8082710fc Mon Sep 17 00:00:00 2001 From: Aemiii91 <44569252+Aemiii91@users.noreply.github.com> Date: Sun, 29 Dec 2024 21:52:24 +0100 Subject: [PATCH 4/4] Update RA patch --- Makefile | 2 +- third-party/RetroArch-patch | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 03a1d063b3..11329bf036 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ TARGET=Onion VERSION=4.4.0 -RA_SUBVERSION=1.19.1-1 +RA_SUBVERSION=1.19.1-2 ########################################################### diff --git a/third-party/RetroArch-patch b/third-party/RetroArch-patch index 4f130bdb55..aaedd182d1 160000 --- a/third-party/RetroArch-patch +++ b/third-party/RetroArch-patch @@ -1 +1 @@ -Subproject commit 4f130bdb5560e76c7d6191458bf8698b36c522fe +Subproject commit aaedd182d17c001f4a63c48798fdafdf380ed473