1 /*
2 * Copyright 2021 Google LLC
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "proxy_server.h"
7
8 #include <signal.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11
12 #include "server/render_protocol.h"
13
14 int
proxy_server_connect(struct proxy_server * srv)15 proxy_server_connect(struct proxy_server *srv)
16 {
17 int client_fd = srv->client_fd;
18 /* transfer ownership */
19 srv->client_fd = -1;
20 return client_fd;
21 }
22
23 void
proxy_server_destroy(struct proxy_server * srv)24 proxy_server_destroy(struct proxy_server *srv)
25 {
26 if (srv->pid >= 0) {
27 kill(srv->pid, SIGKILL);
28
29 siginfo_t siginfo = { 0 };
30 waitid(P_PID, srv->pid, &siginfo, WEXITED);
31 }
32
33 if (srv->client_fd >= 0)
34 close(srv->client_fd);
35
36 free(srv);
37 }
38
39 static bool
proxy_server_fork(struct proxy_server * srv)40 proxy_server_fork(struct proxy_server *srv)
41 {
42 int socket_fds[2];
43 if (!proxy_socket_pair(socket_fds))
44 return false;
45 const int client_fd = socket_fds[0];
46 const int remote_fd = socket_fds[1];
47
48 pid_t pid = fork();
49 if (pid < 0) {
50 proxy_log("failed to fork proxy server");
51 close(client_fd);
52 close(remote_fd);
53 return false;
54 }
55
56 if (pid > 0) {
57 srv->pid = pid;
58 srv->client_fd = client_fd;
59 close(remote_fd);
60 } else {
61 close(client_fd);
62
63 /* do not receive signals from terminal */
64 setpgid(0, 0);
65
66 char fd_str[16];
67 snprintf(fd_str, sizeof(fd_str), "%d", remote_fd);
68
69 char *const argv[] = {
70 RENDER_SERVER_EXEC_PATH,
71 "--socket-fd",
72 fd_str,
73 NULL,
74 };
75 execv(argv[0], argv);
76
77 proxy_log("failed to exec %s: %s", argv[0], strerror(errno));
78 close(remote_fd);
79 exit(-1);
80 }
81
82 return true;
83 }
84
85 static bool
proxy_server_init_fd(struct proxy_server * srv)86 proxy_server_init_fd(struct proxy_server *srv)
87 {
88 /* the fd represents a connection to the server */
89 srv->client_fd = proxy_renderer.cbs->get_server_fd(RENDER_SERVER_VERSION);
90 if (srv->client_fd < 0)
91 return false;
92
93 return true;
94 }
95
96 struct proxy_server *
proxy_server_create(void)97 proxy_server_create(void)
98 {
99 struct proxy_server *srv = calloc(1, sizeof(*srv));
100 if (!srv)
101 return NULL;
102
103 srv->pid = -1;
104
105 if (!proxy_server_init_fd(srv)) {
106 /* start the render server on demand when the client does not provide a
107 * server fd
108 */
109 if (!proxy_server_fork(srv)) {
110 free(srv);
111 return NULL;
112 }
113 }
114
115 if (!proxy_socket_is_seqpacket(srv->client_fd)) {
116 proxy_log("invalid client fd type");
117 close(srv->client_fd);
118 free(srv);
119 return NULL;
120 }
121
122 proxy_log("proxy server with pid %d", srv->pid);
123
124 return srv;
125 }
126