xref: /aosp_15_r20/external/virglrenderer/server/render_server.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*bbecb9d1SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*bbecb9d1SAndroid Build Coastguard Worker  */
5*bbecb9d1SAndroid Build Coastguard Worker 
6*bbecb9d1SAndroid Build Coastguard Worker #include "render_server.h"
7*bbecb9d1SAndroid Build Coastguard Worker 
8*bbecb9d1SAndroid Build Coastguard Worker #include <errno.h>
9*bbecb9d1SAndroid Build Coastguard Worker #include <getopt.h>
10*bbecb9d1SAndroid Build Coastguard Worker #include <poll.h>
11*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
12*bbecb9d1SAndroid Build Coastguard Worker 
13*bbecb9d1SAndroid Build Coastguard Worker #include "render_client.h"
14*bbecb9d1SAndroid Build Coastguard Worker #include "render_worker.h"
15*bbecb9d1SAndroid Build Coastguard Worker 
16*bbecb9d1SAndroid Build Coastguard Worker #define RENDER_SERVER_MAX_WORKER_COUNT 256
17*bbecb9d1SAndroid Build Coastguard Worker 
18*bbecb9d1SAndroid Build Coastguard Worker enum render_server_poll_type {
19*bbecb9d1SAndroid Build Coastguard Worker    RENDER_SERVER_POLL_SOCKET = 0,
20*bbecb9d1SAndroid Build Coastguard Worker    RENDER_SERVER_POLL_SIGCHLD /* optional */,
21*bbecb9d1SAndroid Build Coastguard Worker    RENDER_SERVER_POLL_COUNT,
22*bbecb9d1SAndroid Build Coastguard Worker };
23*bbecb9d1SAndroid Build Coastguard Worker 
24*bbecb9d1SAndroid Build Coastguard Worker static int
render_server_init_poll_fds(struct render_server * srv,struct pollfd poll_fds[static RENDER_SERVER_POLL_COUNT])25*bbecb9d1SAndroid Build Coastguard Worker render_server_init_poll_fds(struct render_server *srv,
26*bbecb9d1SAndroid Build Coastguard Worker                             struct pollfd poll_fds[static RENDER_SERVER_POLL_COUNT])
27*bbecb9d1SAndroid Build Coastguard Worker {
28*bbecb9d1SAndroid Build Coastguard Worker    const int socket_fd = srv->client->socket.fd;
29*bbecb9d1SAndroid Build Coastguard Worker    const int sigchld_fd = render_worker_jail_get_sigchld_fd(srv->worker_jail);
30*bbecb9d1SAndroid Build Coastguard Worker 
31*bbecb9d1SAndroid Build Coastguard Worker    poll_fds[RENDER_SERVER_POLL_SOCKET] = (const struct pollfd){
32*bbecb9d1SAndroid Build Coastguard Worker       .fd = socket_fd,
33*bbecb9d1SAndroid Build Coastguard Worker       .events = POLLIN,
34*bbecb9d1SAndroid Build Coastguard Worker    };
35*bbecb9d1SAndroid Build Coastguard Worker    poll_fds[RENDER_SERVER_POLL_SIGCHLD] = (const struct pollfd){
36*bbecb9d1SAndroid Build Coastguard Worker       .fd = sigchld_fd,
37*bbecb9d1SAndroid Build Coastguard Worker       .events = POLLIN,
38*bbecb9d1SAndroid Build Coastguard Worker    };
39*bbecb9d1SAndroid Build Coastguard Worker 
40*bbecb9d1SAndroid Build Coastguard Worker    return sigchld_fd >= 0 ? 2 : 1;
41*bbecb9d1SAndroid Build Coastguard Worker }
42*bbecb9d1SAndroid Build Coastguard Worker 
43*bbecb9d1SAndroid Build Coastguard Worker static bool
render_server_poll(UNUSED struct render_server * srv,struct pollfd * poll_fds,int poll_fd_count)44*bbecb9d1SAndroid Build Coastguard Worker render_server_poll(UNUSED struct render_server *srv,
45*bbecb9d1SAndroid Build Coastguard Worker                    struct pollfd *poll_fds,
46*bbecb9d1SAndroid Build Coastguard Worker                    int poll_fd_count)
47*bbecb9d1SAndroid Build Coastguard Worker {
48*bbecb9d1SAndroid Build Coastguard Worker    int ret;
49*bbecb9d1SAndroid Build Coastguard Worker    do {
50*bbecb9d1SAndroid Build Coastguard Worker       ret = poll(poll_fds, poll_fd_count, -1);
51*bbecb9d1SAndroid Build Coastguard Worker    } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
52*bbecb9d1SAndroid Build Coastguard Worker 
53*bbecb9d1SAndroid Build Coastguard Worker    if (ret <= 0) {
54*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to poll in the main loop");
55*bbecb9d1SAndroid Build Coastguard Worker       return false;
56*bbecb9d1SAndroid Build Coastguard Worker    }
57*bbecb9d1SAndroid Build Coastguard Worker 
58*bbecb9d1SAndroid Build Coastguard Worker    return true;
59*bbecb9d1SAndroid Build Coastguard Worker }
60*bbecb9d1SAndroid Build Coastguard Worker 
61*bbecb9d1SAndroid Build Coastguard Worker static bool
render_server_run(struct render_server * srv)62*bbecb9d1SAndroid Build Coastguard Worker render_server_run(struct render_server *srv)
63*bbecb9d1SAndroid Build Coastguard Worker {
64*bbecb9d1SAndroid Build Coastguard Worker    struct render_client *client = srv->client;
65*bbecb9d1SAndroid Build Coastguard Worker 
66*bbecb9d1SAndroid Build Coastguard Worker    struct pollfd poll_fds[RENDER_SERVER_POLL_COUNT];
67*bbecb9d1SAndroid Build Coastguard Worker    const int poll_fd_count = render_server_init_poll_fds(srv, poll_fds);
68*bbecb9d1SAndroid Build Coastguard Worker 
69*bbecb9d1SAndroid Build Coastguard Worker    while (srv->state == RENDER_SERVER_STATE_RUN) {
70*bbecb9d1SAndroid Build Coastguard Worker       if (!render_server_poll(srv, poll_fds, poll_fd_count))
71*bbecb9d1SAndroid Build Coastguard Worker          return false;
72*bbecb9d1SAndroid Build Coastguard Worker 
73*bbecb9d1SAndroid Build Coastguard Worker       if (poll_fds[RENDER_SERVER_POLL_SOCKET].revents) {
74*bbecb9d1SAndroid Build Coastguard Worker          if (!render_client_dispatch(client))
75*bbecb9d1SAndroid Build Coastguard Worker             return false;
76*bbecb9d1SAndroid Build Coastguard Worker       }
77*bbecb9d1SAndroid Build Coastguard Worker 
78*bbecb9d1SAndroid Build Coastguard Worker       if (poll_fds[RENDER_SERVER_POLL_SIGCHLD].revents) {
79*bbecb9d1SAndroid Build Coastguard Worker          if (!render_worker_jail_reap_workers(srv->worker_jail))
80*bbecb9d1SAndroid Build Coastguard Worker             return false;
81*bbecb9d1SAndroid Build Coastguard Worker       }
82*bbecb9d1SAndroid Build Coastguard Worker    }
83*bbecb9d1SAndroid Build Coastguard Worker 
84*bbecb9d1SAndroid Build Coastguard Worker    return true;
85*bbecb9d1SAndroid Build Coastguard Worker }
86*bbecb9d1SAndroid Build Coastguard Worker 
87*bbecb9d1SAndroid Build Coastguard Worker static void
render_server_fini(struct render_server * srv)88*bbecb9d1SAndroid Build Coastguard Worker render_server_fini(struct render_server *srv)
89*bbecb9d1SAndroid Build Coastguard Worker {
90*bbecb9d1SAndroid Build Coastguard Worker    if (srv->client)
91*bbecb9d1SAndroid Build Coastguard Worker       render_client_destroy(srv->client);
92*bbecb9d1SAndroid Build Coastguard Worker 
93*bbecb9d1SAndroid Build Coastguard Worker    if (srv->worker_jail)
94*bbecb9d1SAndroid Build Coastguard Worker       render_worker_jail_destroy(srv->worker_jail);
95*bbecb9d1SAndroid Build Coastguard Worker 
96*bbecb9d1SAndroid Build Coastguard Worker    if (srv->client_fd >= 0)
97*bbecb9d1SAndroid Build Coastguard Worker       close(srv->client_fd);
98*bbecb9d1SAndroid Build Coastguard Worker }
99*bbecb9d1SAndroid Build Coastguard Worker 
100*bbecb9d1SAndroid Build Coastguard Worker static bool
render_server_parse_options(struct render_server * srv,int argc,char ** argv)101*bbecb9d1SAndroid Build Coastguard Worker render_server_parse_options(struct render_server *srv, int argc, char **argv)
102*bbecb9d1SAndroid Build Coastguard Worker {
103*bbecb9d1SAndroid Build Coastguard Worker    enum {
104*bbecb9d1SAndroid Build Coastguard Worker       OPT_SOCKET_FD = 'a',
105*bbecb9d1SAndroid Build Coastguard Worker       OPT_WORKER_SECCOMP_BPF,
106*bbecb9d1SAndroid Build Coastguard Worker       OPT_WORKER_SECCOMP_MINIJAIL_POLICY,
107*bbecb9d1SAndroid Build Coastguard Worker       OPT_WORKER_SECCOMP_MINIJAIL_LOG,
108*bbecb9d1SAndroid Build Coastguard Worker       OPT_COUNT,
109*bbecb9d1SAndroid Build Coastguard Worker    };
110*bbecb9d1SAndroid Build Coastguard Worker    static const struct option options[] = {
111*bbecb9d1SAndroid Build Coastguard Worker       { "socket-fd", required_argument, NULL, OPT_SOCKET_FD },
112*bbecb9d1SAndroid Build Coastguard Worker       { "worker-seccomp-bpf", required_argument, NULL, OPT_WORKER_SECCOMP_BPF },
113*bbecb9d1SAndroid Build Coastguard Worker       { "worker-seccomp-minijail-policy", required_argument, NULL,
114*bbecb9d1SAndroid Build Coastguard Worker         OPT_WORKER_SECCOMP_MINIJAIL_POLICY },
115*bbecb9d1SAndroid Build Coastguard Worker       { "worker-seccomp-minijail-log", no_argument, NULL,
116*bbecb9d1SAndroid Build Coastguard Worker         OPT_WORKER_SECCOMP_MINIJAIL_LOG },
117*bbecb9d1SAndroid Build Coastguard Worker       { NULL, 0, NULL, 0 }
118*bbecb9d1SAndroid Build Coastguard Worker    };
119*bbecb9d1SAndroid Build Coastguard Worker    static_assert(OPT_COUNT <= 'z', "");
120*bbecb9d1SAndroid Build Coastguard Worker 
121*bbecb9d1SAndroid Build Coastguard Worker    while (true) {
122*bbecb9d1SAndroid Build Coastguard Worker       const int ret = getopt_long(argc, argv, "", options, NULL);
123*bbecb9d1SAndroid Build Coastguard Worker       if (ret == -1)
124*bbecb9d1SAndroid Build Coastguard Worker          break;
125*bbecb9d1SAndroid Build Coastguard Worker 
126*bbecb9d1SAndroid Build Coastguard Worker       switch (ret) {
127*bbecb9d1SAndroid Build Coastguard Worker       case OPT_SOCKET_FD:
128*bbecb9d1SAndroid Build Coastguard Worker          srv->client_fd = atoi(optarg);
129*bbecb9d1SAndroid Build Coastguard Worker          break;
130*bbecb9d1SAndroid Build Coastguard Worker       case OPT_WORKER_SECCOMP_BPF:
131*bbecb9d1SAndroid Build Coastguard Worker          srv->worker_seccomp_bpf = optarg;
132*bbecb9d1SAndroid Build Coastguard Worker          break;
133*bbecb9d1SAndroid Build Coastguard Worker       case OPT_WORKER_SECCOMP_MINIJAIL_POLICY:
134*bbecb9d1SAndroid Build Coastguard Worker          srv->worker_seccomp_minijail_policy = optarg;
135*bbecb9d1SAndroid Build Coastguard Worker          break;
136*bbecb9d1SAndroid Build Coastguard Worker       case OPT_WORKER_SECCOMP_MINIJAIL_LOG:
137*bbecb9d1SAndroid Build Coastguard Worker          srv->worker_seccomp_minijail_log = true;
138*bbecb9d1SAndroid Build Coastguard Worker          break;
139*bbecb9d1SAndroid Build Coastguard Worker       default:
140*bbecb9d1SAndroid Build Coastguard Worker          render_log("unknown option specified");
141*bbecb9d1SAndroid Build Coastguard Worker          return false;
142*bbecb9d1SAndroid Build Coastguard Worker          break;
143*bbecb9d1SAndroid Build Coastguard Worker       }
144*bbecb9d1SAndroid Build Coastguard Worker    }
145*bbecb9d1SAndroid Build Coastguard Worker 
146*bbecb9d1SAndroid Build Coastguard Worker    if (optind < argc) {
147*bbecb9d1SAndroid Build Coastguard Worker       render_log("non-option arguments specified");
148*bbecb9d1SAndroid Build Coastguard Worker       return false;
149*bbecb9d1SAndroid Build Coastguard Worker    }
150*bbecb9d1SAndroid Build Coastguard Worker 
151*bbecb9d1SAndroid Build Coastguard Worker    if (srv->client_fd < 0 || !render_socket_is_seqpacket(srv->client_fd)) {
152*bbecb9d1SAndroid Build Coastguard Worker       render_log("no valid client fd specified");
153*bbecb9d1SAndroid Build Coastguard Worker       return false;
154*bbecb9d1SAndroid Build Coastguard Worker    }
155*bbecb9d1SAndroid Build Coastguard Worker 
156*bbecb9d1SAndroid Build Coastguard Worker    return true;
157*bbecb9d1SAndroid Build Coastguard Worker }
158*bbecb9d1SAndroid Build Coastguard Worker 
159*bbecb9d1SAndroid Build Coastguard Worker static bool
render_server_init(struct render_server * srv,int argc,char ** argv,struct render_context_args * ctx_args)160*bbecb9d1SAndroid Build Coastguard Worker render_server_init(struct render_server *srv,
161*bbecb9d1SAndroid Build Coastguard Worker                    int argc,
162*bbecb9d1SAndroid Build Coastguard Worker                    char **argv,
163*bbecb9d1SAndroid Build Coastguard Worker                    struct render_context_args *ctx_args)
164*bbecb9d1SAndroid Build Coastguard Worker {
165*bbecb9d1SAndroid Build Coastguard Worker    memset(srv, 0, sizeof(*srv));
166*bbecb9d1SAndroid Build Coastguard Worker    srv->state = RENDER_SERVER_STATE_RUN;
167*bbecb9d1SAndroid Build Coastguard Worker    srv->context_args = ctx_args;
168*bbecb9d1SAndroid Build Coastguard Worker    srv->client_fd = -1;
169*bbecb9d1SAndroid Build Coastguard Worker 
170*bbecb9d1SAndroid Build Coastguard Worker    if (!render_server_parse_options(srv, argc, argv))
171*bbecb9d1SAndroid Build Coastguard Worker       return false;
172*bbecb9d1SAndroid Build Coastguard Worker 
173*bbecb9d1SAndroid Build Coastguard Worker    enum render_worker_jail_seccomp_filter seccomp_filter =
174*bbecb9d1SAndroid Build Coastguard Worker       RENDER_WORKER_JAIL_SECCOMP_NONE;
175*bbecb9d1SAndroid Build Coastguard Worker    const char *seccomp_path = NULL;
176*bbecb9d1SAndroid Build Coastguard Worker    if (srv->worker_seccomp_minijail_log && srv->worker_seccomp_minijail_policy) {
177*bbecb9d1SAndroid Build Coastguard Worker       seccomp_filter = RENDER_WORKER_JAIL_SECCOMP_MINIJAIL_POLICY_LOG;
178*bbecb9d1SAndroid Build Coastguard Worker       seccomp_path = srv->worker_seccomp_minijail_policy;
179*bbecb9d1SAndroid Build Coastguard Worker    } else if (srv->worker_seccomp_bpf) {
180*bbecb9d1SAndroid Build Coastguard Worker       seccomp_filter = RENDER_WORKER_JAIL_SECCOMP_BPF;
181*bbecb9d1SAndroid Build Coastguard Worker       seccomp_path = srv->worker_seccomp_bpf;
182*bbecb9d1SAndroid Build Coastguard Worker    } else if (srv->worker_seccomp_minijail_policy) {
183*bbecb9d1SAndroid Build Coastguard Worker       seccomp_filter = RENDER_WORKER_JAIL_SECCOMP_MINIJAIL_POLICY;
184*bbecb9d1SAndroid Build Coastguard Worker       seccomp_path = srv->worker_seccomp_minijail_policy;
185*bbecb9d1SAndroid Build Coastguard Worker    }
186*bbecb9d1SAndroid Build Coastguard Worker 
187*bbecb9d1SAndroid Build Coastguard Worker    srv->worker_jail = render_worker_jail_create(RENDER_SERVER_MAX_WORKER_COUNT,
188*bbecb9d1SAndroid Build Coastguard Worker                                                 seccomp_filter, seccomp_path);
189*bbecb9d1SAndroid Build Coastguard Worker    if (!srv->worker_jail) {
190*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to create worker jail");
191*bbecb9d1SAndroid Build Coastguard Worker       goto fail;
192*bbecb9d1SAndroid Build Coastguard Worker    }
193*bbecb9d1SAndroid Build Coastguard Worker 
194*bbecb9d1SAndroid Build Coastguard Worker    srv->client = render_client_create(srv, srv->client_fd);
195*bbecb9d1SAndroid Build Coastguard Worker    if (!srv->client) {
196*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to create client");
197*bbecb9d1SAndroid Build Coastguard Worker       goto fail;
198*bbecb9d1SAndroid Build Coastguard Worker    }
199*bbecb9d1SAndroid Build Coastguard Worker    /* ownership transferred */
200*bbecb9d1SAndroid Build Coastguard Worker    srv->client_fd = -1;
201*bbecb9d1SAndroid Build Coastguard Worker 
202*bbecb9d1SAndroid Build Coastguard Worker    return true;
203*bbecb9d1SAndroid Build Coastguard Worker 
204*bbecb9d1SAndroid Build Coastguard Worker fail:
205*bbecb9d1SAndroid Build Coastguard Worker    render_server_fini(srv);
206*bbecb9d1SAndroid Build Coastguard Worker    return false;
207*bbecb9d1SAndroid Build Coastguard Worker }
208*bbecb9d1SAndroid Build Coastguard Worker 
209*bbecb9d1SAndroid Build Coastguard Worker bool
render_server_main(int argc,char ** argv,struct render_context_args * ctx_args)210*bbecb9d1SAndroid Build Coastguard Worker render_server_main(int argc, char **argv, struct render_context_args *ctx_args)
211*bbecb9d1SAndroid Build Coastguard Worker {
212*bbecb9d1SAndroid Build Coastguard Worker    struct render_server srv;
213*bbecb9d1SAndroid Build Coastguard Worker    if (!render_server_init(&srv, argc, argv, ctx_args))
214*bbecb9d1SAndroid Build Coastguard Worker       return false;
215*bbecb9d1SAndroid Build Coastguard Worker 
216*bbecb9d1SAndroid Build Coastguard Worker    const bool ok = render_server_run(&srv);
217*bbecb9d1SAndroid Build Coastguard Worker    render_server_fini(&srv);
218*bbecb9d1SAndroid Build Coastguard Worker 
219*bbecb9d1SAndroid Build Coastguard Worker    return ok;
220*bbecb9d1SAndroid Build Coastguard Worker }
221