x11spice_test.c 4.55 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
/*
    Copyright (C) 2016  Jeremy White <jwhite@codeweavers.com>
    All rights reserved.

    This file is part of x11spice

    x11spice is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    x11spice is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with x11spice.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "xdummy.h"
#include "x11spice_test.h"


static int exec_x11spice(x11spice_server_t *server, gchar *display)
{
36 37
    char buf[4096];
    char *valgrind = getenv("VALGRIND");
38 39 40 41 42

    /* Redirect stderr and stdout to our pipe */
    dup2(server->pipe, fileno(stdout));
    dup2(server->pipe, fileno(stderr));

43
    if (valgrind)
44
        snprintf(buf, sizeof(buf), "%s ../x11spice --display :%s localhost:5900-5999 --hide",
45
                 valgrind, display);
46
    else
47
        snprintf(buf, sizeof(buf), "../x11spice --display :%s localhost:5900-5999 --hide",
48
                 display);
49

50
    return execl("/bin/sh", "sh", "-c", buf, NULL);
51 52 53 54 55

    return -1;
}


56
static void *flush_output(void *opaque)
57 58 59 60 61
{
    x11spice_server_t *server = (x11spice_server_t *) opaque;
    int rc;
    char buf[4096];

62
    while (1) {
63 64 65
        rc = read(server->pipe, buf, sizeof(buf));
        if (rc == -1 && errno == EINTR)
            continue;
66

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
        if (rc <= 0)
            break;

        write(server->logfd, buf, rc);
    }

    close(server->logfd);
    close(server->pipe);

    return NULL;
}

static int get_a_line(char *buf, int len, x11spice_server_t *server)
{
    char *p;

    for (p = buf; p < buf + len; p++)
84 85
        if (*p == '\n') {
            if (p - buf > 4 && memcmp(buf, "URI=", 4) == 0) {
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
                server->uri = g_memdup(buf + 4, p - buf - 4 + 1);
                server->uri[p - buf - 4] = '\0';
                return len;
            }
            return p - buf + 1;
        }

    return 0;
}

int x11spice_start(x11spice_server_t *server, test_t *test)
{
    int fd[2];
    char buf[4096];
    int rc;
    int pos = 0;
    int flush;

    server->running = FALSE;

    if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd))
        return -1;

    server->pid = fork();
110
    if (server->pid == 0) {
111 112 113
        close(fd[0]);
        server->pipe = fd[1];
        exec_x11spice(server, test->xserver->display);
114
        g_warning("x11spice server exec failed.");
115 116
        return -1;
    }
117
    else {
118 119 120 121 122 123 124
        server->pipe = fd[0];
        close(fd[1]);

        if (server->pid == -1)
            return -1;
    }

125 126
    server->logfd = open(test->logfile, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (server->logfd <= 0) {
127 128 129
        x11spice_stop(server);
        return -1;
    }
130

131
    memset(buf, 0, sizeof(buf));
132
    while (!server->uri) {
133 134 135 136
        rc = read(server->pipe, buf + pos, sizeof(buf) - pos);
        if (rc == -1 && errno == EINTR)
            continue;

137
        if (rc <= 0) {
138
            g_warning("x11spice server failed to send signal line.  rc %d, errno %d", rc, errno);
139 140 141 142 143
            return -1;
        }

        pos += rc;

144
        while ((flush = get_a_line(buf, pos, server))) {
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
            write(server->logfd, buf, flush);
            if (flush < pos)
                memmove(buf, buf + flush, pos - flush);
            pos -= flush;
        }
    }

    pthread_create(&server->flush_thread, NULL, flush_output, server);

    server->running = TRUE;
    g_message("x11spice started; pid %d", server->pid);

    return 0;
}

160 161 162 163 164 165 166 167
static void stop_valgrind_children(x11spice_server_t *server)
{
    char buf[256];
    snprintf(buf, sizeof(buf), "kill `ps h --ppid %d -o pid`", server->pid);
    system(buf);
    usleep(100 * 1000L);
}

168 169 170
void x11spice_stop(x11spice_server_t *server)
{
    g_message("server stopping; pid %d", server->pid);
171
    if (server->running) {
172 173 174
        if (getenv("VALGRIND"))
            stop_valgrind_children(server);

175
        if (still_alive(server->pid)) {
176 177 178 179
            kill(server->pid, SIGTERM);
            usleep(50 * 1000);
        }

180
        if (still_alive(server->pid)) {
181 182 183 184 185
            sleep(1);
            kill(server->pid, SIGKILL);
        }
    }
}