1 #include "server.h"
2 
3 #include <errno.h>
4 #include <inttypes.h>
5 #include <libgen.h>
6 #include <stdio.h>
7 #include <SDL2/SDL_assert.h>
8 #include <SDL2/SDL_timer.h>
9 
10 #include "config.h"
11 #include "command.h"
12 #include "log.h"
13 #include "net.h"
14 
15 #define SOCKET_NAME "scrcpy"
16 #define SERVER_FILENAME "scrcpy-server.jar"
17 
18 #define DEFAULT_SERVER_PATH PREFIX "/share/scrcpy/" SERVER_FILENAME
19 #define DEVICE_SERVER_PATH "/data/local/tmp/" SERVER_FILENAME
20 
21 static const char *
get_server_path(void)22 get_server_path(void) {
23     const char *server_path_env = getenv("SCRCPY_SERVER_PATH");
24     if (server_path_env) {
25         LOGD("Using SCRCPY_SERVER_PATH: %s", server_path_env);
26         // if the envvar is set, use it
27         return server_path_env;
28     }
29 
30 #ifndef PORTABLE
31     LOGD("Using server: " DEFAULT_SERVER_PATH);
32     // the absolute path is hardcoded
33     return DEFAULT_SERVER_PATH;
34 #else
35     // use scrcpy-server.jar in the same directory as the executable
36     char *executable_path = get_executable_path();
37     if (!executable_path) {
38         LOGE("Cannot get executable path, "
39              "using " SERVER_FILENAME " from current directory");
40         // not found, use current directory
41         return SERVER_FILENAME;
42     }
43     char *dir = dirname(executable_path);
44     size_t dirlen = strlen(dir);
45 
46     // sizeof(SERVER_FILENAME) gives statically the size including the null byte
47     size_t len = dirlen + 1 + sizeof(SERVER_FILENAME);
48     char *server_path = SDL_malloc(len);
49     if (!server_path) {
50         LOGE("Cannot alloc server path string, "
51              "using " SERVER_FILENAME " from current directory");
52         SDL_free(executable_path);
53         return SERVER_FILENAME;
54     }
55 
56     memcpy(server_path, dir, dirlen);
57     server_path[dirlen] = PATH_SEPARATOR;
58     memcpy(&server_path[dirlen + 1], SERVER_FILENAME, sizeof(SERVER_FILENAME));
59     // the final null byte has been copied with SERVER_FILENAME
60 
61     SDL_free(executable_path);
62 
63     LOGD("Using server (portable): %s", server_path);
64     return server_path;
65 #endif
66 }
67 
68 static bool
push_server(const char * serial)69 push_server(const char *serial) {
70     process_t process = adb_push(serial, get_server_path(), DEVICE_SERVER_PATH);
71     return process_check_success(process, "adb push");
72 }
73 
74 static bool
enable_tunnel_reverse(const char * serial,uint16_t local_port)75 enable_tunnel_reverse(const char *serial, uint16_t local_port) {
76     process_t process = adb_reverse(serial, SOCKET_NAME, local_port);
77     return process_check_success(process, "adb reverse");
78 }
79 
80 static bool
disable_tunnel_reverse(const char * serial)81 disable_tunnel_reverse(const char *serial) {
82     process_t process = adb_reverse_remove(serial, SOCKET_NAME);
83     return process_check_success(process, "adb reverse --remove");
84 }
85 
86 static bool
enable_tunnel_forward(const char * serial,uint16_t local_port)87 enable_tunnel_forward(const char *serial, uint16_t local_port) {
88     process_t process = adb_forward(serial, local_port, SOCKET_NAME);
89     return process_check_success(process, "adb forward");
90 }
91 
92 static bool
disable_tunnel_forward(const char * serial,uint16_t local_port)93 disable_tunnel_forward(const char *serial, uint16_t local_port) {
94     process_t process = adb_forward_remove(serial, local_port);
95     return process_check_success(process, "adb forward --remove");
96 }
97 
98 static bool
enable_tunnel(struct server * server)99 enable_tunnel(struct server *server) {
100     if (enable_tunnel_reverse(server->serial, server->local_port)) {
101         return true;
102     }
103 
104     LOGW("'adb reverse' failed, fallback to 'adb forward'");
105     server->tunnel_forward = true;
106     return enable_tunnel_forward(server->serial, server->local_port);
107 }
108 
109 static bool
disable_tunnel(struct server * server)110 disable_tunnel(struct server *server) {
111     if (server->tunnel_forward) {
112         return disable_tunnel_forward(server->serial, server->local_port);
113     }
114     return disable_tunnel_reverse(server->serial);
115 }
116 
117 static process_t
execute_server(struct server * server,const struct server_params * params)118 execute_server(struct server *server, const struct server_params *params) {
119     char max_size_string[6];
120     char bit_rate_string[11];
121     sprintf(max_size_string, "%"PRIu16, params->max_size);
122     sprintf(bit_rate_string, "%"PRIu32, params->bit_rate);
123     const char *const cmd[] = {
124         "shell",
125         "CLASSPATH=/data/local/tmp/" SERVER_FILENAME,
126         "app_process",
127         "/", // unused
128         "com.genymobile.scrcpy.Server",
129         max_size_string,
130         bit_rate_string,
131         server->tunnel_forward ? "true" : "false",
132         params->crop ? params->crop : "-",
133         params->send_frame_meta ? "true" : "false",
134         params->control ? "true" : "false",
135     };
136     return adb_execute(server->serial, cmd, sizeof(cmd) / sizeof(cmd[0]));
137 }
138 
139 #define IPV4_LOCALHOST 0x7F000001
140 
141 static socket_t
listen_on_port(uint16_t port)142 listen_on_port(uint16_t port) {
143     return net_listen(IPV4_LOCALHOST, port, 1);
144 }
145 
146 static socket_t
connect_and_read_byte(uint16_t port)147 connect_and_read_byte(uint16_t port) {
148     socket_t socket = net_connect(IPV4_LOCALHOST, port);
149     if (socket == INVALID_SOCKET) {
150         return INVALID_SOCKET;
151     }
152 
153     char byte;
154     // the connection may succeed even if the server behind the "adb tunnel"
155     // is not listening, so read one byte to detect a working connection
156     if (net_recv(socket, &byte, 1) != 1) {
157         // the server is not listening yet behind the adb tunnel
158         return INVALID_SOCKET;
159     }
160     return socket;
161 }
162 
163 static socket_t
connect_to_server(uint16_t port,uint32_t attempts,uint32_t delay)164 connect_to_server(uint16_t port, uint32_t attempts, uint32_t delay) {
165     do {
166         LOGD("Remaining connection attempts: %d", (int) attempts);
167         socket_t socket = connect_and_read_byte(port);
168         if (socket != INVALID_SOCKET) {
169             // it worked!
170             return socket;
171         }
172         if (attempts) {
173             SDL_Delay(delay);
174         }
175     } while (--attempts > 0);
176     return INVALID_SOCKET;
177 }
178 
179 static void
close_socket(socket_t * socket)180 close_socket(socket_t *socket) {
181     SDL_assert(*socket != INVALID_SOCKET);
182     net_shutdown(*socket, SHUT_RDWR);
183     if (!net_close(*socket)) {
184         LOGW("Cannot close socket");
185         return;
186     }
187     *socket = INVALID_SOCKET;
188 }
189 
190 void
server_init(struct server * server)191 server_init(struct server *server) {
192     *server = (struct server) SERVER_INITIALIZER;
193 }
194 
195 bool
server_start(struct server * server,const char * serial,const struct server_params * params)196 server_start(struct server *server, const char *serial,
197              const struct server_params *params) {
198     server->local_port = params->local_port;
199 
200     if (serial) {
201         server->serial = SDL_strdup(serial);
202         if (!server->serial) {
203             return false;
204         }
205     }
206 
207     if (!push_server(serial)) {
208         SDL_free(server->serial);
209         return false;
210     }
211 
212     if (!enable_tunnel(server)) {
213         SDL_free(server->serial);
214         return false;
215     }
216 
217     // if "adb reverse" does not work (e.g. over "adb connect"), it fallbacks to
218     // "adb forward", so the app socket is the client
219     if (!server->tunnel_forward) {
220         // At the application level, the device part is "the server" because it
221         // serves video stream and control. However, at the network level, the
222         // client listens and the server connects to the client. That way, the
223         // client can listen before starting the server app, so there is no
224         // need to try to connect until the server socket is listening on the
225         // device.
226 
227         server->server_socket = listen_on_port(params->local_port);
228         if (server->server_socket == INVALID_SOCKET) {
229             LOGE("Could not listen on port %" PRIu16, params->local_port);
230             disable_tunnel(server);
231             SDL_free(server->serial);
232             return false;
233         }
234     }
235 
236     // server will connect to our server socket
237     server->process = execute_server(server, params);
238 
239     if (server->process == PROCESS_NONE) {
240         if (!server->tunnel_forward) {
241             close_socket(&server->server_socket);
242         }
243         disable_tunnel(server);
244         SDL_free(server->serial);
245         return false;
246     }
247 
248     server->tunnel_enabled = true;
249 
250     return true;
251 }
252 
253 bool
server_connect_to(struct server * server)254 server_connect_to(struct server *server) {
255     if (!server->tunnel_forward) {
256         server->video_socket = net_accept(server->server_socket);
257         if (server->video_socket == INVALID_SOCKET) {
258             return false;
259         }
260 
261         server->control_socket = net_accept(server->server_socket);
262         if (server->control_socket == INVALID_SOCKET) {
263             // the video_socket will be clean up on destroy
264             return false;
265         }
266 
267         // we don't need the server socket anymore
268         close_socket(&server->server_socket);
269     } else {
270         uint32_t attempts = 100;
271         uint32_t delay = 100; // ms
272         server->video_socket =
273             connect_to_server(server->local_port, attempts, delay);
274         if (server->video_socket == INVALID_SOCKET) {
275             return false;
276         }
277 
278         // we know that the device is listening, we don't need several attempts
279         server->control_socket =
280             net_connect(IPV4_LOCALHOST, server->local_port);
281         if (server->control_socket == INVALID_SOCKET) {
282             return false;
283         }
284     }
285 
286     // we don't need the adb tunnel anymore
287     disable_tunnel(server); // ignore failure
288     server->tunnel_enabled = false;
289 
290     return true;
291 }
292 
293 void
server_stop(struct server * server)294 server_stop(struct server *server) {
295     if (server->server_socket != INVALID_SOCKET) {
296         close_socket(&server->server_socket);
297     }
298     if (server->video_socket != INVALID_SOCKET) {
299         close_socket(&server->video_socket);
300     }
301     if (server->control_socket != INVALID_SOCKET) {
302         close_socket(&server->control_socket);
303     }
304 
305     SDL_assert(server->process != PROCESS_NONE);
306 
307     if (!cmd_terminate(server->process)) {
308         LOGW("Cannot terminate server");
309     }
310 
311     cmd_simple_wait(server->process, NULL); // ignore exit code
312     LOGD("Server terminated");
313 
314     if (server->tunnel_enabled) {
315         // ignore failure
316         disable_tunnel(server);
317     }
318 }
319 
320 void
server_destroy(struct server * server)321 server_destroy(struct server *server) {
322     SDL_free(server->serial);
323 }
324