From 6f8a41eaf924e7704cd22edacdc28b5fac80c210 Mon Sep 17 00:00:00 2001 From: tareksander <57038324+tareksander@users.noreply.github.com> Date: Wed, 1 Dec 2021 19:01:27 +0100 Subject: [PATCH] Changed: Try to connect over a unix socket to the plugin Fall back to to am if it doesn't work. --- CMakeLists.txt | 2 + scripts/termux-api-start.in | 2 + scripts/termux-api-stop.in | 2 + termux-api.c | 190 +++++++++++++++++++++++++++++++++++- termux-api.h | 1 + 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 scripts/termux-api-start.in create mode 100644 scripts/termux-api-stop.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 77876e0..004e509 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ target_link_libraries(termux-api-broadcast termux-api) # TODO: get list through regex or similar set(script_files + scripts/termux-api-start + scripts/termux-api-stop scripts/termux-audio-info scripts/termux-battery-status scripts/termux-brightness diff --git a/scripts/termux-api-start.in b/scripts/termux-api-start.in new file mode 100644 index 0000000..f06d91d --- /dev/null +++ b/scripts/termux-api-start.in @@ -0,0 +1,2 @@ +#!@TERMUX_PREFIX@/bin/sh +am startservice -n com.termux.api/.KeepAliveService diff --git a/scripts/termux-api-stop.in b/scripts/termux-api-stop.in new file mode 100644 index 0000000..cf23769 --- /dev/null +++ b/scripts/termux-api-stop.in @@ -0,0 +1,2 @@ +#!@TERMUX_PREFIX@/bin/sh +am stopservice -n com.termux.api/.KeepAliveService diff --git a/termux-api.c b/termux-api.c index 48d6ec0..d6d8b5b 100644 --- a/termux-api.c +++ b/termux-api.c @@ -22,6 +22,194 @@ # define PREFIX "/data/data/com.termux/files/usr" #endif +#define LISTEN_SOCKET_ADDRESS "com.termux.api://listen" + +/* passes the arguments to the plugin via the unix socket, falling + * back to exec_am_broadcast() if that doesn't work + */ +_Noreturn void contact_plugin(int argc, char** argv, + char* input_address_string, + char* output_address_string) +{ + // Redirect stdout to /dev/null (but leave stderr open): + close(STDOUT_FILENO); + open("/dev/null", O_RDONLY); + // Close stdin: + close(STDIN_FILENO); + + // ignore SIGPIPE, so am will be called when the connection is closed unexpectedly + struct sigaction sigpipe_action = { + .sa_handler = SIG_IGN, + .sa_flags = 0 + }; + sigaction(SIGPIPE, &sigpipe_action, NULL); + + // try to connect over the listen socket first + int listenfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + if (listenfd != -1) { + struct sockaddr_un listen_addr = { .sun_family = AF_UNIX }; + memcpy(listen_addr.sun_path+1, LISTEN_SOCKET_ADDRESS, strlen(LISTEN_SOCKET_ADDRESS)); + if (connect(listenfd, (struct sockaddr*) &listen_addr, sizeof(sa_family_t) + strlen(LISTEN_SOCKET_ADDRESS) + 1) == 0) { + socklen_t optlen = sizeof(struct ucred); + // check the uid to see if the socket is actually provided by the plugin + struct ucred cred; + if (getsockopt(listenfd, SOL_SOCKET, SO_PEERCRED, &cred, &optlen) == 0 && cred.uid == getuid()) { + + const char insock_str[] = "--es socket_input \""; + const char outsock_str[] = "--es socket_output \""; + const char method_str[] = "--es api_method \""; + + int len = sizeof(insock_str)-1+strlen(output_address_string)+2+sizeof(outsock_str)-1+strlen(input_address_string)+2+sizeof(method_str)-1+strlen(argv[1])+2; + for (int i = 2; i 0) { + int ret = send(listenfd, transmit, totransmit, 0); + if (ret == -1) { + err = true; + break; + } + totransmit -= ret; + } + + // transmit the argument list + if (! err) { + totransmit = len; + transmit = buffer; + while (totransmit > 0) { + int ret = send(listenfd, transmit, totransmit, 0); + if (ret == -1) { + err = true; + break; + } + totransmit -= ret; + } + } + + if (! err) { + char readbuffer[100]; + int ret; + bool first = true; + err = true; + while ((ret = read(listenfd, readbuffer, 99)) > 0) { + // if a single null byte is received as the first message, the call was successfull + if (ret == 1 && readbuffer[0] == 0 && first) { + err = false; + break; + } + // otherwise it's an error message + readbuffer[ret] = '\0'; + // printing out the error is good for debug purposes, but feel free to disable this + fprintf(stderr, "%s", readbuffer); + fflush(stderr); + first = false; + } + } + + // if everything went well, there is no need to call am + if (! err) { + exit(0); + } + } + } + } + + exec_am_broadcast(argc, argv, input_address_string, output_address_string); +} + // Function which execs "am broadcast ..". _Noreturn void exec_am_broadcast(int argc, char** argv, char* input_address_string, @@ -214,7 +402,7 @@ int run_api_command(int argc, char **argv) { perror("fork()"); return -1; } else if (fork_result == 0) - exec_am_broadcast(argc, argv, input_addr_str, output_addr_str); + contact_plugin(argc, argv, input_addr_str, output_addr_str); struct sockaddr_un remote_addr; socklen_t addrlen = sizeof(remote_addr); diff --git a/termux-api.h b/termux-api.h index a0ce789..9c07b3e 100644 --- a/termux-api.h +++ b/termux-api.h @@ -1,6 +1,7 @@ #include _Noreturn void exec_am_broadcast(int, char**, char*, char*); +_Noreturn void contact_plugin(int, char**, char*, char*); _Noreturn void exec_callback(int); void generate_uuid(char*); void* transmit_stdin_to_socket(void*);