xref: /aosp_15_r20/external/virglrenderer/src/proxy/proxy_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 "proxy_socket.h"
7*bbecb9d1SAndroid Build Coastguard Worker 
8*bbecb9d1SAndroid Build Coastguard Worker #include <poll.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 <sys/uio.h>
12*bbecb9d1SAndroid Build Coastguard Worker #include <unistd.h>
13*bbecb9d1SAndroid Build Coastguard Worker 
14*bbecb9d1SAndroid Build Coastguard Worker #define PROXY_SOCKET_MAX_FD_COUNT 8
15*bbecb9d1SAndroid Build Coastguard Worker 
16*bbecb9d1SAndroid Build Coastguard Worker /* this is only used when the render server is started on demand */
17*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_pair(int out_fds[static2])18*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_pair(int out_fds[static 2])
19*bbecb9d1SAndroid Build Coastguard Worker {
20*bbecb9d1SAndroid Build Coastguard Worker    int ret = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, out_fds);
21*bbecb9d1SAndroid Build Coastguard Worker    if (ret) {
22*bbecb9d1SAndroid Build Coastguard Worker       proxy_log("failed to create socket pair");
23*bbecb9d1SAndroid Build Coastguard Worker       return false;
24*bbecb9d1SAndroid Build Coastguard Worker    }
25*bbecb9d1SAndroid Build Coastguard Worker 
26*bbecb9d1SAndroid Build Coastguard Worker    return true;
27*bbecb9d1SAndroid Build Coastguard Worker }
28*bbecb9d1SAndroid Build Coastguard Worker 
29*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_is_seqpacket(int fd)30*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_is_seqpacket(int fd)
31*bbecb9d1SAndroid Build Coastguard Worker {
32*bbecb9d1SAndroid Build Coastguard Worker    int type;
33*bbecb9d1SAndroid Build Coastguard Worker    socklen_t len = sizeof(type);
34*bbecb9d1SAndroid Build Coastguard Worker    if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len)) {
35*bbecb9d1SAndroid Build Coastguard Worker       proxy_log("fd %d err %s", fd, strerror(errno));
36*bbecb9d1SAndroid Build Coastguard Worker       return false;
37*bbecb9d1SAndroid Build Coastguard Worker    }
38*bbecb9d1SAndroid Build Coastguard Worker    return type == SOCK_SEQPACKET;
39*bbecb9d1SAndroid Build Coastguard Worker }
40*bbecb9d1SAndroid Build Coastguard Worker 
41*bbecb9d1SAndroid Build Coastguard Worker void
proxy_socket_init(struct proxy_socket * socket,int fd)42*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_init(struct proxy_socket *socket, int fd)
43*bbecb9d1SAndroid Build Coastguard Worker {
44*bbecb9d1SAndroid Build Coastguard Worker    /* TODO make fd non-blocking and perform io with timeout */
45*bbecb9d1SAndroid Build Coastguard Worker    assert(fd >= 0);
46*bbecb9d1SAndroid Build Coastguard Worker    *socket = (struct proxy_socket){
47*bbecb9d1SAndroid Build Coastguard Worker       .fd = fd,
48*bbecb9d1SAndroid Build Coastguard Worker    };
49*bbecb9d1SAndroid Build Coastguard Worker }
50*bbecb9d1SAndroid Build Coastguard Worker 
51*bbecb9d1SAndroid Build Coastguard Worker void
proxy_socket_fini(struct proxy_socket * socket)52*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_fini(struct proxy_socket *socket)
53*bbecb9d1SAndroid Build Coastguard Worker {
54*bbecb9d1SAndroid Build Coastguard Worker    close(socket->fd);
55*bbecb9d1SAndroid Build Coastguard Worker }
56*bbecb9d1SAndroid Build Coastguard Worker 
57*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_is_connected(const struct proxy_socket * socket)58*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_is_connected(const struct proxy_socket *socket)
59*bbecb9d1SAndroid Build Coastguard Worker {
60*bbecb9d1SAndroid Build Coastguard Worker    struct pollfd poll_fd = {
61*bbecb9d1SAndroid Build Coastguard Worker       .fd = socket->fd,
62*bbecb9d1SAndroid Build Coastguard Worker    };
63*bbecb9d1SAndroid Build Coastguard Worker 
64*bbecb9d1SAndroid Build Coastguard Worker    while (true) {
65*bbecb9d1SAndroid Build Coastguard Worker       const int ret = poll(&poll_fd, 1, 0);
66*bbecb9d1SAndroid Build Coastguard Worker       if (ret == 0) {
67*bbecb9d1SAndroid Build Coastguard Worker          return true;
68*bbecb9d1SAndroid Build Coastguard Worker       } else if (ret < 0) {
69*bbecb9d1SAndroid Build Coastguard Worker          if (errno == EINTR || errno == EAGAIN)
70*bbecb9d1SAndroid Build Coastguard Worker             continue;
71*bbecb9d1SAndroid Build Coastguard Worker 
72*bbecb9d1SAndroid Build Coastguard Worker          proxy_log("failed to poll socket");
73*bbecb9d1SAndroid Build Coastguard Worker          return false;
74*bbecb9d1SAndroid Build Coastguard Worker       }
75*bbecb9d1SAndroid Build Coastguard Worker 
76*bbecb9d1SAndroid Build Coastguard Worker       if (poll_fd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
77*bbecb9d1SAndroid Build Coastguard Worker          proxy_log("socket disconnected");
78*bbecb9d1SAndroid Build Coastguard Worker          return false;
79*bbecb9d1SAndroid Build Coastguard Worker       }
80*bbecb9d1SAndroid Build Coastguard Worker 
81*bbecb9d1SAndroid Build Coastguard Worker       return true;
82*bbecb9d1SAndroid Build Coastguard Worker    }
83*bbecb9d1SAndroid Build Coastguard Worker }
84*bbecb9d1SAndroid Build Coastguard Worker 
85*bbecb9d1SAndroid Build Coastguard Worker static const int *
get_received_fds(const struct msghdr * msg,int * out_count)86*bbecb9d1SAndroid Build Coastguard Worker get_received_fds(const struct msghdr *msg, int *out_count)
87*bbecb9d1SAndroid Build Coastguard Worker {
88*bbecb9d1SAndroid Build Coastguard Worker    const struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
89*bbecb9d1SAndroid Build Coastguard Worker    if (unlikely(!cmsg || cmsg->cmsg_level != SOL_SOCKET ||
90*bbecb9d1SAndroid Build Coastguard Worker                 cmsg->cmsg_type != SCM_RIGHTS || cmsg->cmsg_len < CMSG_LEN(0))) {
91*bbecb9d1SAndroid Build Coastguard Worker       *out_count = 0;
92*bbecb9d1SAndroid Build Coastguard Worker       return NULL;
93*bbecb9d1SAndroid Build Coastguard Worker    }
94*bbecb9d1SAndroid Build Coastguard Worker 
95*bbecb9d1SAndroid Build Coastguard Worker    *out_count = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
96*bbecb9d1SAndroid Build Coastguard Worker    return (const int *)CMSG_DATA(cmsg);
97*bbecb9d1SAndroid Build Coastguard Worker }
98*bbecb9d1SAndroid Build Coastguard Worker 
99*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_socket_recvmsg(struct proxy_socket * socket,struct msghdr * msg)100*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_recvmsg(struct proxy_socket *socket, struct msghdr *msg)
101*bbecb9d1SAndroid Build Coastguard Worker {
102*bbecb9d1SAndroid Build Coastguard Worker    do {
103*bbecb9d1SAndroid Build Coastguard Worker       const ssize_t s = recvmsg(socket->fd, msg, MSG_CMSG_CLOEXEC);
104*bbecb9d1SAndroid Build Coastguard Worker       if (unlikely(s < 0)) {
105*bbecb9d1SAndroid Build Coastguard Worker          if (errno == EAGAIN || errno == EINTR)
106*bbecb9d1SAndroid Build Coastguard Worker             continue;
107*bbecb9d1SAndroid Build Coastguard Worker 
108*bbecb9d1SAndroid Build Coastguard Worker          proxy_log("failed to receive message: %s", strerror(errno));
109*bbecb9d1SAndroid Build Coastguard Worker          return false;
110*bbecb9d1SAndroid Build Coastguard Worker       }
111*bbecb9d1SAndroid Build Coastguard Worker 
112*bbecb9d1SAndroid Build Coastguard Worker       assert(msg->msg_iovlen == 1);
113*bbecb9d1SAndroid Build Coastguard Worker       if (unlikely((msg->msg_flags & (MSG_TRUNC | MSG_CTRUNC)) ||
114*bbecb9d1SAndroid Build Coastguard Worker                    msg->msg_iov[0].iov_len != (size_t)s)) {
115*bbecb9d1SAndroid Build Coastguard Worker          proxy_log("failed to receive message: truncated or incomplete");
116*bbecb9d1SAndroid Build Coastguard Worker 
117*bbecb9d1SAndroid Build Coastguard Worker          int fd_count;
118*bbecb9d1SAndroid Build Coastguard Worker          const int *fds = get_received_fds(msg, &fd_count);
119*bbecb9d1SAndroid Build Coastguard Worker          for (int i = 0; i < fd_count; i++)
120*bbecb9d1SAndroid Build Coastguard Worker             close(fds[i]);
121*bbecb9d1SAndroid Build Coastguard Worker 
122*bbecb9d1SAndroid Build Coastguard Worker          return false;
123*bbecb9d1SAndroid Build Coastguard Worker       }
124*bbecb9d1SAndroid Build Coastguard Worker 
125*bbecb9d1SAndroid Build Coastguard Worker       return true;
126*bbecb9d1SAndroid Build Coastguard Worker    } while (true);
127*bbecb9d1SAndroid Build Coastguard Worker }
128*bbecb9d1SAndroid Build Coastguard Worker 
129*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_socket_receive_reply_internal(struct proxy_socket * socket,void * data,size_t size,int * fds,int max_fd_count,int * out_fd_count)130*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_receive_reply_internal(struct proxy_socket *socket,
131*bbecb9d1SAndroid Build Coastguard Worker                                     void *data,
132*bbecb9d1SAndroid Build Coastguard Worker                                     size_t size,
133*bbecb9d1SAndroid Build Coastguard Worker                                     int *fds,
134*bbecb9d1SAndroid Build Coastguard Worker                                     int max_fd_count,
135*bbecb9d1SAndroid Build Coastguard Worker                                     int *out_fd_count)
136*bbecb9d1SAndroid Build Coastguard Worker {
137*bbecb9d1SAndroid Build Coastguard Worker    assert(data && size);
138*bbecb9d1SAndroid Build Coastguard Worker    struct msghdr msg = {
139*bbecb9d1SAndroid Build Coastguard Worker       .msg_iov =
140*bbecb9d1SAndroid Build Coastguard Worker          &(struct iovec){
141*bbecb9d1SAndroid Build Coastguard Worker             .iov_base = data,
142*bbecb9d1SAndroid Build Coastguard Worker             .iov_len = size,
143*bbecb9d1SAndroid Build Coastguard Worker          },
144*bbecb9d1SAndroid Build Coastguard Worker       .msg_iovlen = 1,
145*bbecb9d1SAndroid Build Coastguard Worker    };
146*bbecb9d1SAndroid Build Coastguard Worker 
147*bbecb9d1SAndroid Build Coastguard Worker    char cmsg_buf[CMSG_SPACE(sizeof(*fds) * PROXY_SOCKET_MAX_FD_COUNT)];
148*bbecb9d1SAndroid Build Coastguard Worker    if (max_fd_count) {
149*bbecb9d1SAndroid Build Coastguard Worker       assert(fds && max_fd_count <= PROXY_SOCKET_MAX_FD_COUNT);
150*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_control = cmsg_buf;
151*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_controllen = CMSG_SPACE(sizeof(*fds) * max_fd_count);
152*bbecb9d1SAndroid Build Coastguard Worker 
153*bbecb9d1SAndroid Build Coastguard Worker       struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
154*bbecb9d1SAndroid Build Coastguard Worker       memset(cmsg, 0, sizeof(*cmsg));
155*bbecb9d1SAndroid Build Coastguard Worker    }
156*bbecb9d1SAndroid Build Coastguard Worker 
157*bbecb9d1SAndroid Build Coastguard Worker    if (!proxy_socket_recvmsg(socket, &msg))
158*bbecb9d1SAndroid Build Coastguard Worker       return false;
159*bbecb9d1SAndroid Build Coastguard Worker 
160*bbecb9d1SAndroid Build Coastguard Worker    if (max_fd_count) {
161*bbecb9d1SAndroid Build Coastguard Worker       int received_fd_count;
162*bbecb9d1SAndroid Build Coastguard Worker       const int *received_fds = get_received_fds(&msg, &received_fd_count);
163*bbecb9d1SAndroid Build Coastguard Worker       assert(received_fd_count <= max_fd_count);
164*bbecb9d1SAndroid Build Coastguard Worker 
165*bbecb9d1SAndroid Build Coastguard Worker       memcpy(fds, received_fds, sizeof(*fds) * received_fd_count);
166*bbecb9d1SAndroid Build Coastguard Worker       *out_fd_count = received_fd_count;
167*bbecb9d1SAndroid Build Coastguard Worker    } else if (out_fd_count) {
168*bbecb9d1SAndroid Build Coastguard Worker       *out_fd_count = 0;
169*bbecb9d1SAndroid Build Coastguard Worker    }
170*bbecb9d1SAndroid Build Coastguard Worker 
171*bbecb9d1SAndroid Build Coastguard Worker    return true;
172*bbecb9d1SAndroid Build Coastguard Worker }
173*bbecb9d1SAndroid Build Coastguard Worker 
174*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_receive_reply(struct proxy_socket * socket,void * data,size_t size)175*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_receive_reply(struct proxy_socket *socket, void *data, size_t size)
176*bbecb9d1SAndroid Build Coastguard Worker {
177*bbecb9d1SAndroid Build Coastguard Worker    return proxy_socket_receive_reply_internal(socket, data, size, NULL, 0, NULL);
178*bbecb9d1SAndroid Build Coastguard Worker }
179*bbecb9d1SAndroid Build Coastguard Worker 
180*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_receive_reply_with_fds(struct proxy_socket * socket,void * data,size_t size,int * fds,int max_fd_count,int * out_fd_count)181*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_receive_reply_with_fds(struct proxy_socket *socket,
182*bbecb9d1SAndroid Build Coastguard Worker                                     void *data,
183*bbecb9d1SAndroid Build Coastguard Worker                                     size_t size,
184*bbecb9d1SAndroid Build Coastguard Worker                                     int *fds,
185*bbecb9d1SAndroid Build Coastguard Worker                                     int max_fd_count,
186*bbecb9d1SAndroid Build Coastguard Worker                                     int *out_fd_count)
187*bbecb9d1SAndroid Build Coastguard Worker {
188*bbecb9d1SAndroid Build Coastguard Worker    return proxy_socket_receive_reply_internal(socket, data, size, fds, max_fd_count,
189*bbecb9d1SAndroid Build Coastguard Worker                                               out_fd_count);
190*bbecb9d1SAndroid Build Coastguard Worker }
191*bbecb9d1SAndroid Build Coastguard Worker 
192*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_socket_sendmsg(struct proxy_socket * socket,const struct msghdr * msg)193*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_sendmsg(struct proxy_socket *socket, const struct msghdr *msg)
194*bbecb9d1SAndroid Build Coastguard Worker {
195*bbecb9d1SAndroid Build Coastguard Worker    do {
196*bbecb9d1SAndroid Build Coastguard Worker       const ssize_t s = sendmsg(socket->fd, msg, MSG_NOSIGNAL);
197*bbecb9d1SAndroid Build Coastguard Worker       if (unlikely(s < 0)) {
198*bbecb9d1SAndroid Build Coastguard Worker          if (errno == EAGAIN || errno == EINTR)
199*bbecb9d1SAndroid Build Coastguard Worker             continue;
200*bbecb9d1SAndroid Build Coastguard Worker 
201*bbecb9d1SAndroid Build Coastguard Worker          proxy_log("failed to send message: %s", strerror(errno));
202*bbecb9d1SAndroid Build Coastguard Worker          return false;
203*bbecb9d1SAndroid Build Coastguard Worker       }
204*bbecb9d1SAndroid Build Coastguard Worker 
205*bbecb9d1SAndroid Build Coastguard Worker       /* no partial send since the socket type is SOCK_SEQPACKET */
206*bbecb9d1SAndroid Build Coastguard Worker       assert(msg->msg_iovlen == 1 && msg->msg_iov[0].iov_len == (size_t)s);
207*bbecb9d1SAndroid Build Coastguard Worker       return true;
208*bbecb9d1SAndroid Build Coastguard Worker    } while (true);
209*bbecb9d1SAndroid Build Coastguard Worker }
210*bbecb9d1SAndroid Build Coastguard Worker 
211*bbecb9d1SAndroid Build Coastguard Worker static bool
proxy_socket_send_request_internal(struct proxy_socket * socket,const void * data,size_t size,const int * fds,int fd_count)212*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_send_request_internal(struct proxy_socket *socket,
213*bbecb9d1SAndroid Build Coastguard Worker                                    const void *data,
214*bbecb9d1SAndroid Build Coastguard Worker                                    size_t size,
215*bbecb9d1SAndroid Build Coastguard Worker                                    const int *fds,
216*bbecb9d1SAndroid Build Coastguard Worker                                    int fd_count)
217*bbecb9d1SAndroid Build Coastguard Worker {
218*bbecb9d1SAndroid Build Coastguard Worker    assert(data && size);
219*bbecb9d1SAndroid Build Coastguard Worker    struct msghdr msg = {
220*bbecb9d1SAndroid Build Coastguard Worker       .msg_iov =
221*bbecb9d1SAndroid Build Coastguard Worker          &(struct iovec){
222*bbecb9d1SAndroid Build Coastguard Worker             .iov_base = (void *)data,
223*bbecb9d1SAndroid Build Coastguard Worker             .iov_len = size,
224*bbecb9d1SAndroid Build Coastguard Worker          },
225*bbecb9d1SAndroid Build Coastguard Worker       .msg_iovlen = 1,
226*bbecb9d1SAndroid Build Coastguard Worker    };
227*bbecb9d1SAndroid Build Coastguard Worker 
228*bbecb9d1SAndroid Build Coastguard Worker    char cmsg_buf[CMSG_SPACE(sizeof(*fds) * PROXY_SOCKET_MAX_FD_COUNT)];
229*bbecb9d1SAndroid Build Coastguard Worker    if (fd_count) {
230*bbecb9d1SAndroid Build Coastguard Worker       assert(fds && fd_count <= PROXY_SOCKET_MAX_FD_COUNT);
231*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_control = cmsg_buf;
232*bbecb9d1SAndroid Build Coastguard Worker       msg.msg_controllen = CMSG_SPACE(sizeof(*fds) * fd_count);
233*bbecb9d1SAndroid Build Coastguard Worker 
234*bbecb9d1SAndroid Build Coastguard Worker       struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
235*bbecb9d1SAndroid Build Coastguard Worker       cmsg->cmsg_level = SOL_SOCKET;
236*bbecb9d1SAndroid Build Coastguard Worker       cmsg->cmsg_type = SCM_RIGHTS;
237*bbecb9d1SAndroid Build Coastguard Worker       cmsg->cmsg_len = CMSG_LEN(sizeof(*fds) * fd_count);
238*bbecb9d1SAndroid Build Coastguard Worker       memcpy(CMSG_DATA(cmsg), fds, sizeof(*fds) * fd_count);
239*bbecb9d1SAndroid Build Coastguard Worker    }
240*bbecb9d1SAndroid Build Coastguard Worker 
241*bbecb9d1SAndroid Build Coastguard Worker    return proxy_socket_sendmsg(socket, &msg);
242*bbecb9d1SAndroid Build Coastguard Worker }
243*bbecb9d1SAndroid Build Coastguard Worker 
244*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_send_request(struct proxy_socket * socket,const void * data,size_t size)245*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_send_request(struct proxy_socket *socket, const void *data, size_t size)
246*bbecb9d1SAndroid Build Coastguard Worker {
247*bbecb9d1SAndroid Build Coastguard Worker    return proxy_socket_send_request_internal(socket, data, size, NULL, 0);
248*bbecb9d1SAndroid Build Coastguard Worker }
249*bbecb9d1SAndroid Build Coastguard Worker 
250*bbecb9d1SAndroid Build Coastguard Worker bool
proxy_socket_send_request_with_fds(struct proxy_socket * socket,const void * data,size_t size,const int * fds,int fd_count)251*bbecb9d1SAndroid Build Coastguard Worker proxy_socket_send_request_with_fds(struct proxy_socket *socket,
252*bbecb9d1SAndroid Build Coastguard Worker                                    const void *data,
253*bbecb9d1SAndroid Build Coastguard Worker                                    size_t size,
254*bbecb9d1SAndroid Build Coastguard Worker                                    const int *fds,
255*bbecb9d1SAndroid Build Coastguard Worker                                    int fd_count)
256*bbecb9d1SAndroid Build Coastguard Worker {
257*bbecb9d1SAndroid Build Coastguard Worker    return proxy_socket_send_request_internal(socket, data, size, fds, fd_count);
258*bbecb9d1SAndroid Build Coastguard Worker }
259