1 /**************************************************************************
2 *
3 * Copyright (C) 2015 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24 #include <stdio.h>
25 #include <signal.h>
26 #include <stdbool.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <sys/un.h>
33 #include <fcntl.h>
34
35 #include "util.h"
36 #include "vtest.h"
37 #include "vtest_protocol.h"
38
vtest_open_socket(const char * path)39 static int vtest_open_socket(const char *path)
40 {
41 struct sockaddr_un un;
42 int sock;
43
44 sock = socket(PF_UNIX, SOCK_STREAM, 0);
45 if (sock < 0) {
46 return -1;
47 }
48
49 memset(&un, 0, sizeof(un));
50 un.sun_family = AF_UNIX;
51
52 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
53
54 unlink(un.sun_path);
55
56 if (bind(sock, (struct sockaddr *)&un, sizeof(un)) < 0) {
57 goto err;
58 }
59
60 if (listen(sock, 1) < 0){
61 goto err;
62 }
63
64 return sock;
65 err:
66 close(sock);
67 return -1;
68 }
69
wait_for_socket_accept(int sock)70 static int wait_for_socket_accept(int sock)
71 {
72 fd_set read_fds;
73 int new_fd;
74 int ret;
75 FD_ZERO(&read_fds);
76 FD_SET(sock, &read_fds);
77
78 ret = select(sock + 1, &read_fds, NULL, NULL, NULL);
79 if (ret < 0)
80 return ret;
81
82 if (FD_ISSET(sock, &read_fds)) {
83 new_fd = accept(sock, NULL, NULL);
84 return new_fd;
85 }
86 return -1;
87 }
88
run_renderer(int in_fd,int out_fd)89 static int run_renderer(int in_fd, int out_fd)
90 {
91 int ret;
92 uint32_t header[VTEST_HDR_SIZE];
93 bool inited = false;
94 again:
95 ret = vtest_wait_for_fd_read(in_fd);
96 if (ret < 0)
97 goto fail;
98
99 ret = vtest_block_read(in_fd, &header, sizeof(header));
100
101 if (ret == 8) {
102 if (!inited) {
103 if (header[1] != VCMD_CREATE_RENDERER)
104 goto fail;
105 ret = vtest_create_renderer(in_fd, out_fd, header[0]);
106 inited = true;
107 }
108 vtest_poll();
109 switch (header[1]) {
110 case VCMD_GET_CAPS:
111 ret = vtest_send_caps();
112 break;
113 case VCMD_RESOURCE_CREATE:
114 ret = vtest_create_resource();
115 break;
116 case VCMD_RESOURCE_UNREF:
117 ret = vtest_resource_unref();
118 break;
119 case VCMD_SUBMIT_CMD:
120 ret = vtest_submit_cmd(header[0]);
121 break;
122 case VCMD_TRANSFER_GET:
123 ret = vtest_transfer_get(header[0]);
124 break;
125 case VCMD_TRANSFER_PUT:
126 ret = vtest_transfer_put(header[0]);
127 break;
128 case VCMD_RESOURCE_BUSY_WAIT:
129 vtest_renderer_create_fence();
130 ret = vtest_resource_busy_wait();
131 break;
132 case VCMD_GET_CAPS2:
133 ret = vtest_send_caps2();
134 break;
135 default:
136 break;
137 }
138
139 if (ret < 0) {
140 goto fail;
141 }
142
143 goto again;
144 }
145 if (ret <= 0) {
146 goto fail;
147 }
148 fail:
149 fprintf(stderr, "socket failed - closing renderer\n");
150 vtest_destroy_renderer();
151 close(in_fd);
152 return 0;
153 }
154
main(int argc,char ** argv)155 int main(int argc, char **argv)
156 {
157 int ret, sock = -1, in_fd, out_fd;
158 pid_t pid;
159 bool do_fork = true, loop = true;
160 struct sigaction sa;
161
162 #ifdef __AFL_LOOP
163 while (__AFL_LOOP(1000)) {
164 #endif
165
166 if (argc > 1) {
167 if (!strcmp(argv[1], "--no-loop-or-fork")) {
168 do_fork = false;
169 loop = false;
170 } else if (!strcmp(argv[1], "--no-fork")) {
171 do_fork = false;
172 } else {
173 ret = open(argv[1], O_RDONLY);
174 if (ret == -1) {
175 perror(0);
176 exit(1);
177 }
178 in_fd = ret;
179 ret = open("/dev/null", O_WRONLY);
180 if (ret == -1) {
181 perror(0);
182 exit(1);
183 }
184 out_fd = ret;
185 loop = false;
186 do_fork = false;
187 goto start;
188 }
189 }
190
191 if (do_fork) {
192 sa.sa_handler = SIG_IGN;
193 sigemptyset(&sa.sa_mask);
194 sa.sa_flags = 0;
195 if (sigaction(SIGCHLD, &sa, 0) == -1) {
196 perror(0);
197 exit(1);
198 }
199 }
200
201 sock = vtest_open_socket("/tmp/.virgl_test");
202 restart:
203 in_fd = wait_for_socket_accept(sock);
204 out_fd = in_fd;
205
206 start:
207 if (do_fork) {
208 /* fork a renderer process */
209 switch ((pid = fork())) {
210 case 0:
211 run_renderer(in_fd, out_fd);
212 exit(0);
213 break;
214 case -1:
215 default:
216 close(in_fd);
217 if (loop)
218 goto restart;
219 }
220 } else {
221 run_renderer(in_fd, out_fd);
222 if (loop)
223 goto restart;
224 }
225
226 if (sock != -1)
227 close(sock);
228 if (in_fd != out_fd)
229 close(out_fd);
230
231 #ifdef __AFL_LOOP
232 }
233 #endif
234 }
235