Skip to content

Commit 6f8a41e

Browse files
tareksanderGrimler91
authored andcommitted
Changed: Try to connect over a unix socket to the plugin
Fall back to to am if it doesn't work.
1 parent 77efa52 commit 6f8a41e

File tree

5 files changed

+196
-1
lines changed

5 files changed

+196
-1
lines changed

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ target_link_libraries(termux-api-broadcast termux-api)
1111

1212
# TODO: get list through regex or similar
1313
set(script_files
14+
scripts/termux-api-start
15+
scripts/termux-api-stop
1416
scripts/termux-audio-info
1517
scripts/termux-battery-status
1618
scripts/termux-brightness

scripts/termux-api-start.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!@TERMUX_PREFIX@/bin/sh
2+
am startservice -n com.termux.api/.KeepAliveService

scripts/termux-api-stop.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!@TERMUX_PREFIX@/bin/sh
2+
am stopservice -n com.termux.api/.KeepAliveService

termux-api.c

Lines changed: 189 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,194 @@
2222
# define PREFIX "/data/data/com.termux/files/usr"
2323
#endif
2424

25+
#define LISTEN_SOCKET_ADDRESS "com.termux.api://listen"
26+
27+
/* passes the arguments to the plugin via the unix socket, falling
28+
* back to exec_am_broadcast() if that doesn't work
29+
*/
30+
_Noreturn void contact_plugin(int argc, char** argv,
31+
char* input_address_string,
32+
char* output_address_string)
33+
{
34+
// Redirect stdout to /dev/null (but leave stderr open):
35+
close(STDOUT_FILENO);
36+
open("/dev/null", O_RDONLY);
37+
// Close stdin:
38+
close(STDIN_FILENO);
39+
40+
// ignore SIGPIPE, so am will be called when the connection is closed unexpectedly
41+
struct sigaction sigpipe_action = {
42+
.sa_handler = SIG_IGN,
43+
.sa_flags = 0
44+
};
45+
sigaction(SIGPIPE, &sigpipe_action, NULL);
46+
47+
// try to connect over the listen socket first
48+
int listenfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
49+
if (listenfd != -1) {
50+
struct sockaddr_un listen_addr = { .sun_family = AF_UNIX };
51+
memcpy(listen_addr.sun_path+1, LISTEN_SOCKET_ADDRESS, strlen(LISTEN_SOCKET_ADDRESS));
52+
if (connect(listenfd, (struct sockaddr*) &listen_addr, sizeof(sa_family_t) + strlen(LISTEN_SOCKET_ADDRESS) + 1) == 0) {
53+
socklen_t optlen = sizeof(struct ucred);
54+
// check the uid to see if the socket is actually provided by the plugin
55+
struct ucred cred;
56+
if (getsockopt(listenfd, SOL_SOCKET, SO_PEERCRED, &cred, &optlen) == 0 && cred.uid == getuid()) {
57+
58+
const char insock_str[] = "--es socket_input \"";
59+
const char outsock_str[] = "--es socket_output \"";
60+
const char method_str[] = "--es api_method \"";
61+
62+
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;
63+
for (int i = 2; i<argc; i++) {
64+
len += strlen(argv[i])+1;
65+
if (strcmp(argv[i], "--es") == 0 || strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--esa") == 0) {
66+
len += 2; // the string extra has to be enclosed in "
67+
}
68+
for (int a = 0; a<strlen(argv[i]); a++) {
69+
if (argv[i][a] == '"') {
70+
len += 1; // " has to be escaped, so one character more.
71+
// This assumes " is only present in string extra arguments, but that is probably an acceptable assumption to make
72+
}
73+
}
74+
}
75+
76+
char* buffer = malloc(len);
77+
78+
int offset = 0;
79+
memcpy(buffer+offset, insock_str, sizeof(insock_str)-1);
80+
offset += sizeof(insock_str)-1;
81+
82+
memcpy(buffer+offset, output_address_string, strlen(output_address_string));
83+
offset += strlen(output_address_string);
84+
85+
buffer[offset] = '"';
86+
offset++;
87+
buffer[offset] = ' ';
88+
offset++;
89+
90+
memcpy(buffer+offset, outsock_str, sizeof(outsock_str)-1);
91+
offset += sizeof(outsock_str)-1;
92+
93+
memcpy(buffer+offset, input_address_string, strlen(input_address_string));
94+
offset += strlen(input_address_string);
95+
96+
buffer[offset] = '"';
97+
offset++;
98+
buffer[offset] = ' ';
99+
offset++;
100+
101+
memcpy(buffer+offset, method_str, sizeof(method_str)-1);
102+
offset += sizeof(method_str)-1;
103+
104+
memcpy(buffer+offset, argv[1], strlen(argv[1]));
105+
offset += strlen(argv[1]);
106+
107+
buffer[offset] = '"';
108+
offset++;
109+
buffer[offset] = ' ';
110+
offset++;
111+
112+
for (int i = 2; i<argc; i++) {
113+
if (strcmp(argv[i], "--es") == 0 || strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--esa") == 0) {
114+
memcpy(buffer+offset, argv[i], strlen(argv[i]));
115+
offset += strlen(argv[i]);
116+
buffer[offset] = ' ';
117+
offset++;
118+
i++;
119+
if (i < argc) {
120+
memcpy(buffer+offset, argv[i], strlen(argv[i]));
121+
offset += strlen(argv[i]);
122+
buffer[offset] = ' ';
123+
offset++;
124+
}
125+
i++;
126+
if (i < argc) {
127+
buffer[offset] = '"';
128+
offset++;
129+
for (int a = 0; a<strlen(argv[i]); a++) {
130+
if (argv[i][a] == '"') {
131+
buffer[offset] = '\\';
132+
offset++;
133+
buffer[offset] = '"';
134+
offset++;
135+
} else {
136+
buffer[offset] = argv[i][a];
137+
offset++;
138+
}
139+
}
140+
buffer[offset] = '"';
141+
offset++;
142+
buffer[offset] = ' ';
143+
offset++;
144+
}
145+
} else {
146+
memcpy(buffer+offset, argv[i], strlen(argv[i]));
147+
offset += strlen(argv[i]);
148+
buffer[offset] = ' ';
149+
offset++;
150+
}
151+
}
152+
153+
int netlen = htons(len);
154+
155+
bool err = false;
156+
// transmit the size
157+
int totransmit = 2;
158+
void* transmit = &netlen;
159+
while (totransmit > 0) {
160+
int ret = send(listenfd, transmit, totransmit, 0);
161+
if (ret == -1) {
162+
err = true;
163+
break;
164+
}
165+
totransmit -= ret;
166+
}
167+
168+
// transmit the argument list
169+
if (! err) {
170+
totransmit = len;
171+
transmit = buffer;
172+
while (totransmit > 0) {
173+
int ret = send(listenfd, transmit, totransmit, 0);
174+
if (ret == -1) {
175+
err = true;
176+
break;
177+
}
178+
totransmit -= ret;
179+
}
180+
}
181+
182+
if (! err) {
183+
char readbuffer[100];
184+
int ret;
185+
bool first = true;
186+
err = true;
187+
while ((ret = read(listenfd, readbuffer, 99)) > 0) {
188+
// if a single null byte is received as the first message, the call was successfull
189+
if (ret == 1 && readbuffer[0] == 0 && first) {
190+
err = false;
191+
break;
192+
}
193+
// otherwise it's an error message
194+
readbuffer[ret] = '\0';
195+
// printing out the error is good for debug purposes, but feel free to disable this
196+
fprintf(stderr, "%s", readbuffer);
197+
fflush(stderr);
198+
first = false;
199+
}
200+
}
201+
202+
// if everything went well, there is no need to call am
203+
if (! err) {
204+
exit(0);
205+
}
206+
}
207+
}
208+
}
209+
210+
exec_am_broadcast(argc, argv, input_address_string, output_address_string);
211+
}
212+
25213
// Function which execs "am broadcast ..".
26214
_Noreturn void exec_am_broadcast(int argc, char** argv,
27215
char* input_address_string,
@@ -214,7 +402,7 @@ int run_api_command(int argc, char **argv) {
214402
perror("fork()");
215403
return -1;
216404
} else if (fork_result == 0)
217-
exec_am_broadcast(argc, argv, input_addr_str, output_addr_str);
405+
contact_plugin(argc, argv, input_addr_str, output_addr_str);
218406

219407
struct sockaddr_un remote_addr;
220408
socklen_t addrlen = sizeof(remote_addr);

termux-api.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <stdlib.h>
22

33
_Noreturn void exec_am_broadcast(int, char**, char*, char*);
4+
_Noreturn void contact_plugin(int, char**, char*, char*);
45
_Noreturn void exec_callback(int);
56
void generate_uuid(char*);
67
void* transmit_stdin_to_socket(void*);

0 commit comments

Comments
 (0)