cscg24-guacamole

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

terminal-stdin-stream.c (5330B)


      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 "terminal/common.h"
     21#include "terminal/terminal.h"
     22#include "terminal/terminal-priv.h"
     23
     24#include <guacamole/protocol.h>
     25#include <guacamole/socket.h>
     26#include <guacamole/user.h>
     27
     28/**
     29 * Handler for "blob" instructions which writes the data of received
     30 * blobs to STDIN of the terminal associated with the stream.
     31 *
     32 * @see guac_user_blob_handler
     33 */
     34static int guac_terminal_input_stream_blob_handler(guac_user* user,
     35        guac_stream* stream, void* data, int length) {
     36
     37    guac_terminal* term = (guac_terminal*) stream->data;
     38
     39    /* Attempt to write received data */
     40    guac_terminal_lock(term);
     41    int result = guac_terminal_write_all(term->stdin_pipe_fd[1], data, length);
     42    guac_terminal_unlock(term);
     43
     44    /* Acknowledge receipt of data and result of write attempt */
     45    if (result <= 0) {
     46
     47        guac_user_log(user, GUAC_LOG_DEBUG,
     48                "Attempt to write to STDIN via an inbound stream failed.");
     49
     50        guac_protocol_send_ack(user->socket, stream,
     51                "Attempt to write to STDIN failed.",
     52                GUAC_PROTOCOL_STATUS_SUCCESS);
     53
     54    }
     55    else {
     56
     57        guac_user_log(user, GUAC_LOG_DEBUG,
     58                "%i bytes successfully written to STDIN from an inbound stream.",
     59                length);
     60
     61        guac_protocol_send_ack(user->socket, stream,
     62                "Data written to STDIN.",
     63                GUAC_PROTOCOL_STATUS_SUCCESS);
     64
     65    }
     66
     67    guac_socket_flush(user->socket);
     68    return 0;
     69
     70}
     71
     72/**
     73 * Handler for "end" instructions which disassociates the given
     74 * stream from the terminal, allowing user input to resume.
     75 *
     76 * @see guac_user_end_handler
     77 */
     78static int guac_terminal_input_stream_end_handler(guac_user* user,
     79        guac_stream* stream) {
     80
     81    guac_terminal* term = (guac_terminal*) stream->data;
     82
     83    /* Reset input stream, unblocking user input */
     84    guac_terminal_lock(term);
     85    term->input_stream = NULL;
     86    guac_terminal_unlock(term);
     87
     88    guac_user_log(user, GUAC_LOG_DEBUG, "Inbound stream closed. User input "
     89            "will now resume affecting STDIN.");
     90
     91    return 0;
     92
     93}
     94
     95/**
     96 * Internal implementation of guac_terminal_send_stream() which assumes
     97 * that the guac_terminal has already been locked through a call to
     98 * guac_terminal_lock(). The semantics of all parameters and the return
     99 * value are identical to guac_terminal_send_stream().
    100 *
    101 * @see guac_terminal_send_stream()
    102 */
    103static int __guac_terminal_send_stream(guac_terminal* term, guac_user* user,
    104        guac_stream* stream) {
    105
    106    /* Deny redirecting STDIN if terminal is not started */
    107    if (!term->started) {
    108
    109        guac_user_log(user, GUAC_LOG_DEBUG, "Attempt to direct the contents "
    110                "of an inbound stream to STDIN denied. The terminal is not "
    111                "yet ready for input.");
    112
    113        guac_protocol_send_ack(user->socket, stream,
    114                "Terminal not yet started.",
    115                GUAC_PROTOCOL_STATUS_RESOURCE_CONFLICT);
    116
    117        guac_socket_flush(user->socket);
    118        return 1;
    119
    120    }
    121
    122    /* If a stream is already being used for STDIN, deny creation of
    123     * further streams */
    124    if (term->input_stream != NULL) {
    125
    126        guac_user_log(user, GUAC_LOG_DEBUG, "Attempt to direct the contents "
    127                "of an inbound stream to STDIN denied. STDIN is already "
    128                "being read from an inbound stream.");
    129
    130        guac_protocol_send_ack(user->socket, stream,
    131                "STDIN is already being read from a stream.",
    132                GUAC_PROTOCOL_STATUS_RESOURCE_CONFLICT);
    133
    134        guac_socket_flush(user->socket);
    135        return 1;
    136
    137    }
    138
    139    guac_user_log(user, GUAC_LOG_DEBUG, "Now reading STDIN from inbound "
    140            "stream. User input will no longer affect STDIN until the "
    141            "stream is closed.");
    142
    143    stream->blob_handler = guac_terminal_input_stream_blob_handler;
    144    stream->end_handler = guac_terminal_input_stream_end_handler;
    145    stream->data = term;
    146
    147    /* Block user input until stream is ended */
    148    term->input_stream = stream;
    149
    150    /* Acknowledge redirection from stream */
    151    guac_protocol_send_ack(user->socket, stream,
    152            "Now reading STDIN from stream.",
    153            GUAC_PROTOCOL_STATUS_SUCCESS);
    154
    155    guac_socket_flush(user->socket);
    156    return 0;
    157
    158}
    159
    160int guac_terminal_send_stream(guac_terminal* term, guac_user* user,
    161        guac_stream* stream) {
    162
    163    int result;
    164
    165    guac_terminal_lock(term);
    166    result = __guac_terminal_send_stream(term, user, stream);
    167    guac_terminal_unlock(term);
    168
    169    return result;
    170
    171}
    172