cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

interpret.c (4589B)


      1/*
      2 * Licensed to the Apache Software Foundation (ASF) under one
      3 * or more contributor license agreements.  See the NOTICE file
      4 * distributed with this work for additional information
      5 * regarding copyright ownership.  The ASF licenses this file
      6 * to you under the Apache License, Version 2.0 (the
      7 * "License"); you may not use this file except in compliance
      8 * with the License.  You may obtain a copy of the License at
      9 *
     10 *   http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing,
     13 * software distributed under the License is distributed on an
     14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     15 * KIND, either express or implied.  See the License for the
     16 * specific language governing permissions and limitations
     17 * under the License.
     18 */
     19
     20#include "config.h"
     21#include "instructions.h"
     22#include "log.h"
     23#include "state.h"
     24
     25#include <guacamole/client.h>
     26#include <guacamole/error.h>
     27#include <guacamole/parser.h>
     28#include <guacamole/socket.h>
     29
     30#include <sys/stat.h>
     31#include <sys/types.h>
     32#include <errno.h>
     33#include <fcntl.h>
     34#include <stdbool.h>
     35#include <string.h>
     36#include <unistd.h>
     37
     38/**
     39 * Reads and handles all Guacamole instructions from the given guac_socket
     40 * until end-of-stream is reached.
     41 *
     42 * @param state
     43 *     The current state of the Guacamole input log interpreter.
     44 *
     45 * @param path
     46 *     The name of the file being parsed (for logging purposes). This file
     47 *     must already be open and available through the given socket.
     48 *
     49 * @param socket
     50 *     The guac_socket through which instructions should be read.
     51 *
     52 * @return
     53 *     Zero on success, non-zero if parsing of Guacamole protocol data through
     54 *     the given socket fails.
     55 */
     56static int guaclog_read_instructions(guaclog_state* state,
     57        const char* path, guac_socket* socket) {
     58
     59    /* Obtain Guacamole protocol parser */
     60    guac_parser* parser = guac_parser_alloc();
     61    if (parser == NULL)
     62        return 1;
     63
     64    /* Continuously read and handle all instructions */
     65    while (!guac_parser_read(parser, socket, -1)) {
     66        guaclog_handle_instruction(state, parser->opcode,
     67                parser->argc, parser->argv);
     68    }
     69
     70    /* Fail on read/parse error */
     71    if (guac_error != GUAC_STATUS_CLOSED) {
     72        guaclog_log(GUAC_LOG_ERROR, "%s: %s",
     73                path, guac_status_string(guac_error));
     74        guac_parser_free(parser);
     75        return 1;
     76    }
     77
     78    /* Parse complete */
     79    guac_parser_free(parser);
     80    return 0;
     81
     82}
     83
     84int guaclog_interpret(const char* path, const char* out_path, bool force) {
     85
     86    /* Open input file */
     87    int fd = open(path, O_RDONLY);
     88    if (fd < 0) {
     89        guaclog_log(GUAC_LOG_ERROR, "%s: %s", path, strerror(errno));
     90        return 1;
     91    }
     92
     93    /* Lock entire input file for reading by the current process */
     94    struct flock file_lock = {
     95        .l_type   = F_RDLCK,
     96        .l_whence = SEEK_SET,
     97        .l_start  = 0,
     98        .l_len    = 0,
     99        .l_pid    = getpid()
    100    };
    101
    102    /* Abort if file cannot be locked for reading */
    103    if (!force && fcntl(fd, F_SETLK, &file_lock) == -1) {
    104
    105        /* Warn if lock cannot be acquired */
    106        if (errno == EACCES || errno == EAGAIN)
    107            guaclog_log(GUAC_LOG_WARNING, "Refusing to interpret log of "
    108                    "in-progress session \"%s\" (specify the -f option to "
    109                    "override this behavior).", path);
    110
    111        /* Log an error if locking fails in an unexpected way */
    112        else
    113            guaclog_log(GUAC_LOG_ERROR, "Cannot lock \"%s\" for reading: %s",
    114                    path, strerror(errno));
    115
    116        close(fd);
    117        return 1;
    118    }
    119
    120    /* Allocate input state for interpreting process */
    121    guaclog_state* state = guaclog_state_alloc(out_path);
    122    if (state == NULL) {
    123        close(fd);
    124        return 1;
    125    }
    126
    127    /* Obtain guac_socket wrapping file descriptor */
    128    guac_socket* socket = guac_socket_open(fd);
    129    if (socket == NULL) {
    130        guaclog_log(GUAC_LOG_ERROR, "%s: %s", path,
    131                guac_status_string(guac_error));
    132        close(fd);
    133        guaclog_state_free(state);
    134        return 1;
    135    }
    136
    137    guaclog_log(GUAC_LOG_INFO, "Writing input events from \"%s\" "
    138            "to \"%s\" ...", path, out_path);
    139
    140    /* Attempt to read all instructions in the file */
    141    if (guaclog_read_instructions(state, path, socket)) {
    142        guac_socket_free(socket);
    143        guaclog_state_free(state);
    144        return 1;
    145    }
    146
    147    /* Close input and finish interpreting process */
    148    guac_socket_free(socket);
    149    return guaclog_state_free(state);
    150
    151}
    152