Home | History | Annotate | Download | only in vtest
      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 
     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 
     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 
     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 
    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