xref: /aosp_15_r20/external/virglrenderer/server/render_socket.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_socket.h"
7*bbecb9d1SAndroid Build Coastguard Worker 
8*bbecb9d1SAndroid Build Coastguard Worker #include <errno.h>
9*bbecb9d1SAndroid Build Coastguard Worker #include <sys/socket.h>
10*bbecb9d1SAndroid Build Coastguard Worker #include <sys/types.h>
11*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
12*bbecb9d1SAndroid Build Coastguard Worker 
13*bbecb9d1SAndroid Build Coastguard Worker #define RENDER_SOCKET_MAX_FD_COUNT 8
14*bbecb9d1SAndroid Build Coastguard Worker 
15*bbecb9d1SAndroid Build Coastguard Worker /* The socket pair between the server process and the client process is set up
16*bbecb9d1SAndroid Build Coastguard Worker  * by the client process (or yet another process).  Because render_server_run
17*bbecb9d1SAndroid Build Coastguard Worker  * does not poll yet, the fd is expected to be blocking.
18*bbecb9d1SAndroid Build Coastguard Worker  *
19*bbecb9d1SAndroid Build Coastguard Worker  * We also expect the fd to be always valid.  If the client process dies, the
20*bbecb9d1SAndroid Build Coastguard Worker  * fd becomes invalid and is considered a fatal error.
21*bbecb9d1SAndroid Build Coastguard Worker  *
22*bbecb9d1SAndroid Build Coastguard Worker  * There is also a socket pair between each context worker and the client
23*bbecb9d1SAndroid Build Coastguard Worker  * process.  The pair is set up by render_socket_pair here.
24*bbecb9d1SAndroid Build Coastguard Worker  *
25*bbecb9d1SAndroid Build Coastguard Worker  * The fd is also expected to be blocking.  When the client process closes its
26*bbecb9d1SAndroid Build Coastguard Worker  * end of the socket pair, the context worker terminates.
27*bbecb9d1SAndroid Build Coastguard Worker  */
28*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_pair(int out_fds[static2])29*bbecb9d1SAndroid Build Coastguard Worker render_socket_pair(int out_fds[static 2])
30*bbecb9d1SAndroid Build Coastguard Worker {
31*bbecb9d1SAndroid Build Coastguard Worker    int ret = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, out_fds);
32*bbecb9d1SAndroid Build Coastguard Worker    if (ret) {
33*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to create socket pair");
34*bbecb9d1SAndroid Build Coastguard Worker       return false;
35*bbecb9d1SAndroid Build Coastguard Worker    }
36*bbecb9d1SAndroid Build Coastguard Worker 
37*bbecb9d1SAndroid Build Coastguard Worker    return true;
38*bbecb9d1SAndroid Build Coastguard Worker }
39*bbecb9d1SAndroid Build Coastguard Worker 
40*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_is_seqpacket(int fd)41*bbecb9d1SAndroid Build Coastguard Worker render_socket_is_seqpacket(int fd)
42*bbecb9d1SAndroid Build Coastguard Worker {
43*bbecb9d1SAndroid Build Coastguard Worker    int type;
44*bbecb9d1SAndroid Build Coastguard Worker    socklen_t len = sizeof(type);
45*bbecb9d1SAndroid Build Coastguard Worker    if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
46*bbecb9d1SAndroid Build Coastguard Worker       return false;
47*bbecb9d1SAndroid Build Coastguard Worker    return type == SOCK_SEQPACKET;
48*bbecb9d1SAndroid Build Coastguard Worker }
49*bbecb9d1SAndroid Build Coastguard Worker 
50*bbecb9d1SAndroid Build Coastguard Worker void
render_socket_init(struct render_socket * socket,int fd)51*bbecb9d1SAndroid Build Coastguard Worker render_socket_init(struct render_socket *socket, int fd)
52*bbecb9d1SAndroid Build Coastguard Worker {
53*bbecb9d1SAndroid Build Coastguard Worker    assert(fd >= 0);
54*bbecb9d1SAndroid Build Coastguard Worker    *socket = (struct render_socket){
55*bbecb9d1SAndroid Build Coastguard Worker       .fd = fd,
56*bbecb9d1SAndroid Build Coastguard Worker    };
57*bbecb9d1SAndroid Build Coastguard Worker }
58*bbecb9d1SAndroid Build Coastguard Worker 
59*bbecb9d1SAndroid Build Coastguard Worker void
render_socket_fini(struct render_socket * socket)60*bbecb9d1SAndroid Build Coastguard Worker render_socket_fini(struct render_socket *socket)
61*bbecb9d1SAndroid Build Coastguard Worker {
62*bbecb9d1SAndroid Build Coastguard Worker    close(socket->fd);
63*bbecb9d1SAndroid Build Coastguard Worker }
64*bbecb9d1SAndroid Build Coastguard Worker 
65*bbecb9d1SAndroid Build Coastguard Worker static const int *
get_received_fds(const struct msghdr * msg,int * out_count)66*bbecb9d1SAndroid Build Coastguard Worker get_received_fds(const struct msghdr *msg, int *out_count)
67*bbecb9d1SAndroid Build Coastguard Worker {
68*bbecb9d1SAndroid Build Coastguard Worker    const struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
69*bbecb9d1SAndroid Build Coastguard Worker    if (unlikely(!cmsg || cmsg->cmsg_level != SOL_SOCKET ||
70*bbecb9d1SAndroid Build Coastguard Worker                 cmsg->cmsg_type != SCM_RIGHTS || cmsg->cmsg_len < CMSG_LEN(0))) {
71*bbecb9d1SAndroid Build Coastguard Worker       *out_count = 0;
72*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
73*bbecb9d1SAndroid Build Coastguard Worker    }
74*bbecb9d1SAndroid Build Coastguard Worker 
75*bbecb9d1SAndroid Build Coastguard Worker    *out_count = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
76*bbecb9d1SAndroid Build Coastguard Worker    return (const int *)CMSG_DATA(cmsg);
77*bbecb9d1SAndroid Build Coastguard Worker }
78*bbecb9d1SAndroid Build Coastguard Worker 
79*bbecb9d1SAndroid Build Coastguard Worker static bool
render_socket_recvmsg(struct render_socket * socket,struct msghdr * msg,size_t * out_size)80*bbecb9d1SAndroid Build Coastguard Worker render_socket_recvmsg(struct render_socket *socket, struct msghdr *msg, size_t *out_size)
81*bbecb9d1SAndroid Build Coastguard Worker {
82*bbecb9d1SAndroid Build Coastguard Worker    do {
83*bbecb9d1SAndroid Build Coastguard Worker       const ssize_t s = recvmsg(socket->fd, msg, MSG_CMSG_CLOEXEC);
84*bbecb9d1SAndroid Build Coastguard Worker       if (unlikely(s <= 0)) {
85*bbecb9d1SAndroid Build Coastguard Worker          if (!s)
86*bbecb9d1SAndroid Build Coastguard Worker             return false;
87*bbecb9d1SAndroid Build Coastguard Worker 
88*bbecb9d1SAndroid Build Coastguard Worker          if (errno == EAGAIN || errno == EINTR)
89*bbecb9d1SAndroid Build Coastguard Worker             continue;
90*bbecb9d1SAndroid Build Coastguard Worker 
91*bbecb9d1SAndroid Build Coastguard Worker          render_log("failed to receive message: %s", strerror(errno));
92*bbecb9d1SAndroid Build Coastguard Worker          return false;
93*bbecb9d1SAndroid Build Coastguard Worker       }
94*bbecb9d1SAndroid Build Coastguard Worker 
95*bbecb9d1SAndroid Build Coastguard Worker       if (unlikely(msg->msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
96*bbecb9d1SAndroid Build Coastguard Worker          render_log("failed to receive message: truncated");
97*bbecb9d1SAndroid Build Coastguard Worker 
98*bbecb9d1SAndroid Build Coastguard Worker          int fd_count;
99*bbecb9d1SAndroid Build Coastguard Worker          const int *fds = get_received_fds(msg, &fd_count);
100*bbecb9d1SAndroid Build Coastguard Worker          for (int i = 0; i < fd_count; i++)
101*bbecb9d1SAndroid Build Coastguard Worker             close(fds[i]);
102*bbecb9d1SAndroid Build Coastguard Worker 
103*bbecb9d1SAndroid Build Coastguard Worker          return false;
104*bbecb9d1SAndroid Build Coastguard Worker       }
105*bbecb9d1SAndroid Build Coastguard Worker 
106*bbecb9d1SAndroid Build Coastguard Worker       *out_size = s;
107*bbecb9d1SAndroid Build Coastguard Worker       return true;
108*bbecb9d1SAndroid Build Coastguard Worker    } while (true);
109*bbecb9d1SAndroid Build Coastguard Worker }
110*bbecb9d1SAndroid Build Coastguard Worker 
111*bbecb9d1SAndroid Build Coastguard Worker static bool
render_socket_receive_request_internal(struct render_socket * socket,void * data,size_t max_size,size_t * out_size,int * fds,int max_fd_count,int * out_fd_count)112*bbecb9d1SAndroid Build Coastguard Worker render_socket_receive_request_internal(struct render_socket *socket,
113*bbecb9d1SAndroid Build Coastguard Worker                                        void *data,
114*bbecb9d1SAndroid Build Coastguard Worker                                        size_t max_size,
115*bbecb9d1SAndroid Build Coastguard Worker                                        size_t *out_size,
116*bbecb9d1SAndroid Build Coastguard Worker                                        int *fds,
117*bbecb9d1SAndroid Build Coastguard Worker                                        int max_fd_count,
118*bbecb9d1SAndroid Build Coastguard Worker                                        int *out_fd_count)
119*bbecb9d1SAndroid Build Coastguard Worker {
120*bbecb9d1SAndroid Build Coastguard Worker    assert(data && max_size);
121*bbecb9d1SAndroid Build Coastguard Worker    struct msghdr msg = {
122*bbecb9d1SAndroid Build Coastguard Worker       .msg_iov =
123*bbecb9d1SAndroid Build Coastguard Worker          &(struct iovec){
124*bbecb9d1SAndroid Build Coastguard Worker             .iov_base = data,
125*bbecb9d1SAndroid Build Coastguard Worker             .iov_len = max_size,
126*bbecb9d1SAndroid Build Coastguard Worker          },
127*bbecb9d1SAndroid Build Coastguard Worker       .msg_iovlen = 1,
128*bbecb9d1SAndroid Build Coastguard Worker    };
129*bbecb9d1SAndroid Build Coastguard Worker 
130*bbecb9d1SAndroid Build Coastguard Worker    char cmsg_buf[CMSG_SPACE(sizeof(*fds) * RENDER_SOCKET_MAX_FD_COUNT)];
131*bbecb9d1SAndroid Build Coastguard Worker    if (max_fd_count) {
132*bbecb9d1SAndroid Build Coastguard Worker       assert(fds && max_fd_count <= RENDER_SOCKET_MAX_FD_COUNT);
133*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_control = cmsg_buf;
134*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_controllen = CMSG_SPACE(sizeof(*fds) * max_fd_count);
135*bbecb9d1SAndroid Build Coastguard Worker 
136*bbecb9d1SAndroid Build Coastguard Worker       struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
137*bbecb9d1SAndroid Build Coastguard Worker       memset(cmsg, 0, sizeof(*cmsg));
138*bbecb9d1SAndroid Build Coastguard Worker    }
139*bbecb9d1SAndroid Build Coastguard Worker 
140*bbecb9d1SAndroid Build Coastguard Worker    if (!render_socket_recvmsg(socket, &msg, out_size))
141*bbecb9d1SAndroid Build Coastguard Worker       return false;
142*bbecb9d1SAndroid Build Coastguard Worker 
143*bbecb9d1SAndroid Build Coastguard Worker    if (max_fd_count) {
144*bbecb9d1SAndroid Build Coastguard Worker       int received_fd_count;
145*bbecb9d1SAndroid Build Coastguard Worker       const int *received_fds = get_received_fds(&msg, &received_fd_count);
146*bbecb9d1SAndroid Build Coastguard Worker       assert(received_fd_count <= max_fd_count);
147*bbecb9d1SAndroid Build Coastguard Worker 
148*bbecb9d1SAndroid Build Coastguard Worker       memcpy(fds, received_fds, sizeof(*fds) * received_fd_count);
149*bbecb9d1SAndroid Build Coastguard Worker       *out_fd_count = received_fd_count;
150*bbecb9d1SAndroid Build Coastguard Worker    } else if (out_fd_count) {
151*bbecb9d1SAndroid Build Coastguard Worker       *out_fd_count = 0;
152*bbecb9d1SAndroid Build Coastguard Worker    }
153*bbecb9d1SAndroid Build Coastguard Worker 
154*bbecb9d1SAndroid Build Coastguard Worker    return true;
155*bbecb9d1SAndroid Build Coastguard Worker }
156*bbecb9d1SAndroid Build Coastguard Worker 
157*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_receive_request(struct render_socket * socket,void * data,size_t max_size,size_t * out_size)158*bbecb9d1SAndroid Build Coastguard Worker render_socket_receive_request(struct render_socket *socket,
159*bbecb9d1SAndroid Build Coastguard Worker                               void *data,
160*bbecb9d1SAndroid Build Coastguard Worker                               size_t max_size,
161*bbecb9d1SAndroid Build Coastguard Worker                               size_t *out_size)
162*bbecb9d1SAndroid Build Coastguard Worker {
163*bbecb9d1SAndroid Build Coastguard Worker    return render_socket_receive_request_internal(socket, data, max_size, out_size, NULL,
164*bbecb9d1SAndroid Build Coastguard Worker                                                  0, NULL);
165*bbecb9d1SAndroid Build Coastguard Worker }
166*bbecb9d1SAndroid Build Coastguard Worker 
167*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_receive_request_with_fds(struct render_socket * socket,void * data,size_t max_size,size_t * out_size,int * fds,int max_fd_count,int * out_fd_count)168*bbecb9d1SAndroid Build Coastguard Worker render_socket_receive_request_with_fds(struct render_socket *socket,
169*bbecb9d1SAndroid Build Coastguard Worker                                        void *data,
170*bbecb9d1SAndroid Build Coastguard Worker                                        size_t max_size,
171*bbecb9d1SAndroid Build Coastguard Worker                                        size_t *out_size,
172*bbecb9d1SAndroid Build Coastguard Worker                                        int *fds,
173*bbecb9d1SAndroid Build Coastguard Worker                                        int max_fd_count,
174*bbecb9d1SAndroid Build Coastguard Worker                                        int *out_fd_count)
175*bbecb9d1SAndroid Build Coastguard Worker {
176*bbecb9d1SAndroid Build Coastguard Worker    return render_socket_receive_request_internal(socket, data, max_size, out_size, fds,
177*bbecb9d1SAndroid Build Coastguard Worker                                                  max_fd_count, out_fd_count);
178*bbecb9d1SAndroid Build Coastguard Worker }
179*bbecb9d1SAndroid Build Coastguard Worker 
180*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_receive_data(struct render_socket * socket,void * data,size_t size)181*bbecb9d1SAndroid Build Coastguard Worker render_socket_receive_data(struct render_socket *socket, void *data, size_t size)
182*bbecb9d1SAndroid Build Coastguard Worker {
183*bbecb9d1SAndroid Build Coastguard Worker    size_t received_size;
184*bbecb9d1SAndroid Build Coastguard Worker    if (!render_socket_receive_request(socket, data, size, &received_size))
185*bbecb9d1SAndroid Build Coastguard Worker       return false;
186*bbecb9d1SAndroid Build Coastguard Worker 
187*bbecb9d1SAndroid Build Coastguard Worker    if (size != received_size) {
188*bbecb9d1SAndroid Build Coastguard Worker       render_log("failed to receive data: expected %zu but received %zu", size,
189*bbecb9d1SAndroid Build Coastguard Worker                  received_size);
190*bbecb9d1SAndroid Build Coastguard Worker       return false;
191*bbecb9d1SAndroid Build Coastguard Worker    }
192*bbecb9d1SAndroid Build Coastguard Worker 
193*bbecb9d1SAndroid Build Coastguard Worker    return true;
194*bbecb9d1SAndroid Build Coastguard Worker }
195*bbecb9d1SAndroid Build Coastguard Worker 
196*bbecb9d1SAndroid Build Coastguard Worker static bool
render_socket_sendmsg(struct render_socket * socket,const struct msghdr * msg)197*bbecb9d1SAndroid Build Coastguard Worker render_socket_sendmsg(struct render_socket *socket, const struct msghdr *msg)
198*bbecb9d1SAndroid Build Coastguard Worker {
199*bbecb9d1SAndroid Build Coastguard Worker    do {
200*bbecb9d1SAndroid Build Coastguard Worker       const ssize_t s = sendmsg(socket->fd, msg, MSG_NOSIGNAL);
201*bbecb9d1SAndroid Build Coastguard Worker       if (unlikely(s < 0)) {
202*bbecb9d1SAndroid Build Coastguard Worker          if (errno == EAGAIN || errno == EINTR)
203*bbecb9d1SAndroid Build Coastguard Worker             continue;
204*bbecb9d1SAndroid Build Coastguard Worker 
205*bbecb9d1SAndroid Build Coastguard Worker          render_log("failed to send message: %s", strerror(errno));
206*bbecb9d1SAndroid Build Coastguard Worker          return false;
207*bbecb9d1SAndroid Build Coastguard Worker       }
208*bbecb9d1SAndroid Build Coastguard Worker 
209*bbecb9d1SAndroid Build Coastguard Worker       /* no partial send since the socket type is SOCK_SEQPACKET */
210*bbecb9d1SAndroid Build Coastguard Worker       assert(msg->msg_iovlen == 1 && msg->msg_iov[0].iov_len == (size_t)s);
211*bbecb9d1SAndroid Build Coastguard Worker       return true;
212*bbecb9d1SAndroid Build Coastguard Worker    } while (true);
213*bbecb9d1SAndroid Build Coastguard Worker }
214*bbecb9d1SAndroid Build Coastguard Worker 
215*bbecb9d1SAndroid Build Coastguard Worker static inline bool
render_socket_send_reply_internal(struct render_socket * socket,const void * data,size_t size,const int * fds,int fd_count)216*bbecb9d1SAndroid Build Coastguard Worker render_socket_send_reply_internal(struct render_socket *socket,
217*bbecb9d1SAndroid Build Coastguard Worker                                   const void *data,
218*bbecb9d1SAndroid Build Coastguard Worker                                   size_t size,
219*bbecb9d1SAndroid Build Coastguard Worker                                   const int *fds,
220*bbecb9d1SAndroid Build Coastguard Worker                                   int fd_count)
221*bbecb9d1SAndroid Build Coastguard Worker {
222*bbecb9d1SAndroid Build Coastguard Worker    assert(data && size);
223*bbecb9d1SAndroid Build Coastguard Worker    struct msghdr msg = {
224*bbecb9d1SAndroid Build Coastguard Worker       .msg_iov =
225*bbecb9d1SAndroid Build Coastguard Worker          &(struct iovec){
226*bbecb9d1SAndroid Build Coastguard Worker             .iov_base = (void *)data,
227*bbecb9d1SAndroid Build Coastguard Worker             .iov_len = size,
228*bbecb9d1SAndroid Build Coastguard Worker          },
229*bbecb9d1SAndroid Build Coastguard Worker       .msg_iovlen = 1,
230*bbecb9d1SAndroid Build Coastguard Worker    };
231*bbecb9d1SAndroid Build Coastguard Worker 
232*bbecb9d1SAndroid Build Coastguard Worker    char cmsg_buf[CMSG_SPACE(sizeof(*fds) * RENDER_SOCKET_MAX_FD_COUNT)];
233*bbecb9d1SAndroid Build Coastguard Worker    if (fd_count) {
234*bbecb9d1SAndroid Build Coastguard Worker       assert(fds && fd_count <= RENDER_SOCKET_MAX_FD_COUNT);
235*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_control = cmsg_buf;
236*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_controllen = CMSG_SPACE(sizeof(*fds) * fd_count);
237*bbecb9d1SAndroid Build Coastguard Worker 
238*bbecb9d1SAndroid Build Coastguard Worker       struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
239*bbecb9d1SAndroid Build Coastguard Worker       cmsg->cmsg_level = SOL_SOCKET;
240*bbecb9d1SAndroid Build Coastguard Worker       cmsg->cmsg_type = SCM_RIGHTS;
241*bbecb9d1SAndroid Build Coastguard Worker       cmsg->cmsg_len = CMSG_LEN(sizeof(*fds) * fd_count);
242*bbecb9d1SAndroid Build Coastguard Worker       memcpy(CMSG_DATA(cmsg), fds, sizeof(*fds) * fd_count);
243*bbecb9d1SAndroid Build Coastguard Worker    }
244*bbecb9d1SAndroid Build Coastguard Worker 
245*bbecb9d1SAndroid Build Coastguard Worker    return render_socket_sendmsg(socket, &msg);
246*bbecb9d1SAndroid Build Coastguard Worker }
247*bbecb9d1SAndroid Build Coastguard Worker 
248*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_send_reply(struct render_socket * socket,const void * data,size_t size)249*bbecb9d1SAndroid Build Coastguard Worker render_socket_send_reply(struct render_socket *socket, const void *data, size_t size)
250*bbecb9d1SAndroid Build Coastguard Worker {
251*bbecb9d1SAndroid Build Coastguard Worker    return render_socket_send_reply_internal(socket, data, size, NULL, 0);
252*bbecb9d1SAndroid Build Coastguard Worker }
253*bbecb9d1SAndroid Build Coastguard Worker 
254*bbecb9d1SAndroid Build Coastguard Worker bool
render_socket_send_reply_with_fds(struct render_socket * socket,const void * data,size_t size,const int * fds,int fd_count)255*bbecb9d1SAndroid Build Coastguard Worker render_socket_send_reply_with_fds(struct render_socket *socket,
256*bbecb9d1SAndroid Build Coastguard Worker                                   const void *data,
257*bbecb9d1SAndroid Build Coastguard Worker                                   size_t size,
258*bbecb9d1SAndroid Build Coastguard Worker                                   const int *fds,
259*bbecb9d1SAndroid Build Coastguard Worker                                   int fd_count)
260*bbecb9d1SAndroid Build Coastguard Worker {
261*bbecb9d1SAndroid Build Coastguard Worker    return render_socket_send_reply_internal(socket, data, size, fds, fd_count);
262*bbecb9d1SAndroid Build Coastguard Worker }
263