Esempio n. 1
0
/*
  forked program
*/
static int fork_helper(void)
{
	pid_t pid;
	int i, client, max_rounds = 10;

	pid = fork();
	if (pid == -1) {
		DEBUG(DEBUG_CRIT,("Unable to fork: %s\n", strerror(errno)));
		return -1;
	}
	if (pid == 0) { // Child
		client = socket_client_connect();
		if (client < 0) {
			exit(1);
		}
		socket_client_write(client);
		for (i = 1 ; i <= max_rounds ; i++ ) {
			DEBUG(DEBUG_DEBUG,("Child process waiting ( %d/%d)\n", i, max_rounds));
			sleep(1);
		}
		socket_client_close(client);
		exit(0);
	} else {
		globals.helper_pid = pid;
	}
	return 0;
}
Esempio n. 2
0
/* Checks if a packet size is correct */
int check_size(int length, int target, char* error) {
    if (length != target) {
        error("Invalid %s packet (%d != %d)", error, length, target);
        socket_client_close(0);
        return 0;
    }
    return 1;
}
Esempio n. 3
0
/* Unrequested data came in from WebSocket client. */
static void socket_client_read() {
    char buffer[BUFFERSIZE];
    int length;

    length = socket_client_read_frame(buffer, sizeof(buffer));
    if (length < 0) {
        socket_client_close(1);
        return;
    }

    if (length >= BUFFERSIZE) {
        error("Unrequested command too long: (>%d bytes).", length);
        socket_client_close(1);
        return;
    }

    /* Ignore return value (connection gets closed on error) */
    socket_client_handle_unrequested(buffer, length);
}
Esempio n. 4
0
int main(int argc, char** argv) {
    int c;
    while ((c = getopt(argc, argv, "v:")) != -1) {
        switch (c) {
        case 'v':
            verbose = atoi(optarg);
            break;
        default:
            usage(argv[0]);
        }
    }

    if (optind != argc-1)
        usage(argv[0]);

    char* display = argv[optind];

    trueorabort(display[0] == ':', "Invalid display: '%s'", display);

    char* endptr;
    int displaynum = (int)strtol(display+1, &endptr, 10);
    trueorabort(display+1 != endptr && (*endptr == '\0' || *endptr == '.'),
                "Invalid display number: '%s'", display);

    init_display(display);
    socket_server_init(PORT_BASE + displaynum);

    unsigned char buffer[BUFFERSIZE];
    int length;

    while (1) {
        set_connected(dpy, False);
        socket_server_accept(VERSION);
        write_init();
        set_connected(dpy, True);
        while (1) {
            length = socket_client_read_frame((char*)buffer, sizeof(buffer));
            if (length < 0) {
                socket_client_close(1);
                break;
            }

            if (length < 1) {
                error("Invalid packet from client (size <1).");
                socket_client_close(0);
                break;
            }

            switch (buffer[0]) {
            case 'S':  /* Screen */
                if (!check_size(length, sizeof(struct screen), "screen"))
                    break;
                write_image((struct screen*)buffer);
                break;
            case 'P':  /* Cursor */
                if (!check_size(length, sizeof(struct cursor), "cursor"))
                    break;
                write_cursor();
                break;
            case 'R':  /* Resolution */
                if (!check_size(length, sizeof(struct resolution),
                                "resolution"))
                    break;
                change_resolution((struct resolution*)buffer);
                break;
            case 'K': {  /* Key */
                if (!check_size(length, sizeof(struct key), "key"))
                    break;
                struct key* k = (struct key*)buffer;
                log(2, "Key: kc=%04x\n", k->keycode);
                XTestFakeKeyEvent(dpy, k->keycode, k->down, CurrentTime);
                if (k->down) {
                    kb_add(KEYBOARD, k->keycode);
                } else {
                    kb_remove(KEYBOARD, k->keycode);
                }
                break;
            }
            case 'C': {  /* Click */
                if (!check_size(length, sizeof(struct mouseclick),
                                "mouseclick"))
                    break;
                struct mouseclick* mc = (struct mouseclick*)buffer;
                XTestFakeButtonEvent(dpy, mc->button, mc->down, CurrentTime);
                if (mc->down) {
                    kb_add(MOUSE, mc->button);
                } else {
                    kb_remove(MOUSE, mc->button);
                }
                break;
            }
            case 'M': {  /* Mouse move */
                if (!check_size(length, sizeof(struct mousemove), "mousemove"))
                    break;
                struct mousemove* mm = (struct mousemove*)buffer;
                XTestFakeMotionEvent(dpy, 0, mm->x, mm->y, CurrentTime);
                break;
            }
            case 'Q':  /* "Quit": release all keys */
                kb_release_all();
                break;
            default:
                error("Invalid packet from client (%d).", buffer[0]);
                socket_client_close(0);
            }
        }
        socket_client_close(0);
        kb_release_all();
        close_mmap(&cache[0]);
        close_mmap(&cache[1]);
    }

    return 0;
}
Esempio n. 5
0
int main(int argc, char **argv) {
    int n;
    /* Poll array:
     * 0 - server_fd
     * 1 - pipein_fd
     * 2 - client_fd (if any)
     */
    struct pollfd fds[3];
    int nfds = 3;
    sigset_t sigmask;
    sigset_t sigmask_orig;
    struct sigaction act;
    int c;

    while ((c = getopt(argc, argv, "v:")) != -1) {
        switch (c) {
        case 'v':
            verbose = atoi(optarg);
            break;
        default:
            fprintf(stderr, "%s [-v 0-3]\n", argv[0]);
            return 1;
        }
    }

    /* Termination signal handler. */
    memset(&act, 0, sizeof(act));
    act.sa_handler = signal_handler;

    if (sigaction(SIGHUP, &act, 0) < 0 ||
        sigaction(SIGINT, &act, 0) < 0 ||
        sigaction(SIGTERM, &act, 0) < 0) {
        syserror("sigaction error.");
        return 2;
    }

    /* Ignore SIGPIPE in all cases: it may happen, since we write to pipes, but
     * it is not fatal. */
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGPIPE);

    if (sigprocmask(SIG_BLOCK, &sigmask, NULL) < 0) {
        syserror("sigprocmask error.");
        return 2;
    }

    /* Ignore terminating signals, except when ppoll is running. Save current
     * mask in sigmask_orig. */
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGHUP);
    sigaddset(&sigmask, SIGINT);
    sigaddset(&sigmask, SIGTERM);

    if (sigprocmask(SIG_BLOCK, &sigmask, &sigmask_orig) < 0) {
        syserror("sigprocmask error.");
        return 2;
    }

    /* Prepare pollfd structure. */
    memset(fds, 0, sizeof(fds));
    fds[0].events = POLLIN;
    fds[1].events = POLLIN;
    fds[2].events = POLLIN;

    /* Initialise pipe and WebSocket server */
    socket_server_init(PORT);
    pipe_init();

    while (!terminate) {
        /* Make sure fds is up to date. */
        fds[0].fd = server_fd;
        fds[1].fd = pipein_fd;
        fds[2].fd = client_fd;

        /* Only handle signals in ppoll: this makes sure we complete processing
         * the current request before bailing out. */
        n = ppoll(fds, nfds, NULL, &sigmask_orig);

        log(3, "poll ret=%d (%d, %d, %d)\n", n,
                   fds[0].revents, fds[1].revents, fds[2].revents);

        if (n < 0) {
            /* Do not print error when ppoll is interupted by a signal. */
            if (errno != EINTR || verbose >= 1)
                syserror("ppoll error.");
            break;
        }

        if (fds[0].revents & POLLIN) {
            log(1, "WebSocket accept.");
            socket_server_accept(VERSION);
            n--;
        }
        if (fds[1].revents & POLLIN) {
            log(2, "Pipe fd ready.");
            pipein_read();
            n--;
        }
        if (fds[2].revents & POLLIN) {
            log(2, "Client fd ready.");
            socket_client_read();
            n--;
        }

        if (n > 0) { /* Some events were not handled, this is a problem */
            error("Some poll events could not be handled: "
                    "ret=%d (%d, %d, %d).",
                    n, fds[0].revents, fds[1].revents, fds[2].revents);
            break;
        }
    }

    log(1, "Terminating...");

    if (client_fd)
        socket_client_close(1);

    return 0;
}
Esempio n. 6
0
/* Handle unrequested packet from extension.
 * Returns 0 on success. On error, returns -1 and closes websocket connection.
 */
static int socket_client_handle_unrequested(const char* buffer,
                                            const int length) {
    /* Process the client request. */
    switch (buffer[0]) {
        case 'C': {  /* Send a command to croutoncycle */
            char reply[BUFFERSIZE];
            int replylength = 1;
            reply[FRAMEMAXHEADERSIZE] = 'C';

            char* cmd = "croutoncycle";
            char param[length];
            memcpy(param, buffer+1, length-1);
            param[length-1] = '\0';
            char* args[] = { cmd, param, NULL };

            log(2, "Received croutoncycle command (%s)", param);

            /* We are only interested in the output for list commands */
            if (param[0] == 'l') {
                int n = popen2(cmd, args, NULL, 0,
                               &reply[FRAMEMAXHEADERSIZE+1],
                               BUFFERSIZE-FRAMEMAXHEADERSIZE-1);
                if (n < 0) {
                    error("Call to croutoncycle failed.");
                    socket_client_close(0);
                    return -1;
                }
                replylength += n;
            } else if (param[0] == 'O') {
                /* Extra OK response from a C back-and-forth. Disregard. */
                break;
            } else {
                /* Launch command in background (this is necessary as
                   croutoncycle may send a websocket command, leaving us
                   deadlocked...) */
                pid_t pid = fork();
                if (pid < 0) {
                    syserror("Fork error.");
                    exit(1);
                } else if (pid == 0) {
                    /* Double-fork to avoid zombies */
                    pid_t pid2 = fork();
                    if (pid2 < 0) {
                        syserror("Fork error.");
                        exit(1);
                    } else if (pid2 == 0) {
                        execvp(cmd, args);
                        error("Error running '%s'.", cmd);
                        exit(127);
                    }
                    exit(0);
                }
                /* Wait for first fork to complete. */
                waitpid(pid, NULL, 0);
            }
            if (socket_client_write_frame(reply, replylength,
                                          WS_OPCODE_TEXT, 1) < 0) {
                error("Write error.");
                socket_client_close(0);
                return -1;
            }
            break;
        }
        default: {
            int len = length > 64 ? 64 : length;
            char dump[len+1];
            memcpy(dump, buffer, len);
            dump[len] = '\0';
            error("Received an unexpected packet from client (%s).", dump);
            socket_client_close(0);
            return -1;
        }
    }

    return 0;
}
Esempio n. 7
0
/* Read data from the pipe, and forward it to the socket client. */
static void pipein_read() {
    int n;
    char buffer[FRAMEMAXHEADERSIZE+BUFFERSIZE];
    int first = 1;
    char firstchar = '\0';

    if (client_fd < 0) {
        log(1, "No client FD.");
        pipein_reopen();
        pipeout_error("EError: not connected.");
        return;
    }

    while (1) {
        n = read(pipein_fd, buffer+FRAMEMAXHEADERSIZE, BUFFERSIZE);
        log(3, "n=%d", n);

        if (n < 0) {
            /* This is very unlikely, and fatal. */
            syserror("Error reading from pipe.");
            exit(1);
        } else if (n == 0) {
            break;
        }

        if (first)
            firstchar = buffer[FRAMEMAXHEADERSIZE];

        /* Write a text frame for the first packet, then cont frames. */
        n = socket_client_write_frame(buffer, n,
                                  first ? WS_OPCODE_TEXT : WS_OPCODE_CONT, 0);
        if (n < 0) {
            error("Error writing frame.");
            pipein_reopen();
            pipeout_error("EError: socket write error.");
            return;
        }

        first = 0;
    }

    log(3, "EOF");

    pipein_reopen();

    /* Empty FIN frame to finish the message. */
    n = socket_client_write_frame(buffer, 0,
                                  first ? WS_OPCODE_TEXT : WS_OPCODE_CONT, 1);
    if (n < 0) {
        error("Error writing frame.");
        pipeout_error("EError: socket write error");
        return;
    }

    log(2, "Reading answer from client...");

    int fin = 0;
    uint32_t maskkey;
    int retry = 0;
    first = 1;

    /* Ignore return value, so we still read the frame even if pipeout
     * cannot be open. */
    pipeout_open();

    /* Read possibly fragmented message from WebSocket. */
    while (fin != 1) {
        int len = socket_client_read_frame_header(&fin, &maskkey, &retry);

        log(3, "len=%d fin=%d retry=%d...", len, fin, retry);

        if (retry)
            continue;

        if (len < 0)
            goto exit;

        /* Read the whole frame, and write it to pipeout */
        while (len > 0) {
            int rlen = (len > BUFFERSIZE) ? BUFFERSIZE: len;
            if (socket_client_read_frame_data(buffer, rlen, maskkey) < 0)
                goto exit;

            /* Check first byte */
            if (first && buffer[0] != firstchar && buffer[0] != 'E') {
                /* This is not a response: unrequested packet */
                if (!fin && len < BUFFERSIZE) {
                    /* !fin, and buffer not full, finish reading... */
                    rlen = socket_client_read_frame(buffer+len,
                                                    sizeof(buffer)-len);
                    if (rlen < 0)
                        goto exit;

                    len += rlen;
                }

                if (len >= BUFFERSIZE) {
                    error("Unrequested command too long: (>%d bytes).", len);
                    socket_client_close(1);
                    goto exit;
                }

                if (socket_client_handle_unrequested(buffer, len) < 0)
                    goto exit;

                /* Command was handled, try reading the answer again. */
                fin = 0;
                break;
            }

            /* Ignore return value as well */
            pipeout_write(buffer, rlen);
            len -= rlen;
            first = 0;
        }
    }

exit:
    pipeout_close();
}