cscg24-guacamole

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

nested_send_instruction.c (4467B)


      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 <CUnit/CUnit.h>
     21#include <guacamole/protocol.h>
     22#include <guacamole/socket.h>
     23
     24#include <stdlib.h>
     25#include <unistd.h>
     26
     27/**
     28 * Test string which contains exactly four Unicode characters encoded in UTF-8.
     29 * This particular test string uses several characters which encode to multiple
     30 * bytes in UTF-8.
     31 */
     32#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1"
     33
     34/**
     35 * Writes a series of Guacamole instructions using a nested guac_socket
     36 * wrapping another guac_socket which writes to the given file descriptor. The
     37 * instructions written correspond to the instructions verified by
     38 * read_expected_instructions(). The given file descriptor is automatically
     39 * closed as a result of calling this function.
     40 *
     41 * @param fd
     42 *     The file descriptor to write instructions to.
     43 */
     44static void write_instructions(int fd) {
     45
     46    /* Open guac socket */
     47    guac_socket* socket = guac_socket_open(fd);
     48
     49    /* Write nothing if socket cannot be allocated (test will fail in parent
     50     * process due to failure to read) */
     51    if (socket == NULL) {
     52        close(fd);
     53        return;
     54    }
     55
     56    /* Nest socket */
     57    guac_socket* nested_socket = guac_socket_nest(socket, 123);
     58
     59    /* Write nothing if nested socket cannot be allocated (test will fail in
     60     * parent process due to failure to read) */
     61    if (socket == NULL) {
     62        guac_socket_free(socket);
     63        return;
     64    }
     65
     66    /* Write instructions */
     67    guac_protocol_send_name(nested_socket, "a" UTF8_4 "b" UTF8_4 "c");
     68    guac_protocol_send_sync(nested_socket, 12345);
     69
     70    /* Close and free sockets */
     71    guac_socket_free(nested_socket);
     72    guac_socket_free(socket);
     73
     74}
     75
     76/**
     77 * Reads raw bytes from the given file descriptor until no further bytes
     78 * remain, verifying that those bytes represent the series of Guacamole
     79 * instructions expected to be written by write_instructions(). The given
     80 * file descriptor is automatically closed as a result of calling this
     81 * function.
     82 *
     83 * @param fd
     84 *     The file descriptor to read data from.
     85 */
     86static void read_expected_instructions(int fd) {
     87
     88    char expected[] =
     89        "4.nest,3.123,37."
     90            "4.name,11.a" UTF8_4 "b" UTF8_4 "c;"
     91            "4.sync,5.12345;"
     92        ";";
     93
     94    int numread;
     95    char buffer[1024];
     96    int offset = 0;
     97
     98    /* Read everything available into buffer */
     99    while ((numread = read(fd, &(buffer[offset]),
    100                    sizeof(buffer) - offset)) > 0) {
    101        offset += numread;
    102    }
    103
    104    /* Verify length of read data */
    105    CU_ASSERT_EQUAL(offset, strlen(expected));
    106
    107    /* Add NULL terminator */
    108    buffer[offset] = '\0';
    109
    110    /* Read value should be equal to expected value */
    111    CU_ASSERT_STRING_EQUAL(buffer, expected);
    112
    113    /* File descriptor is no longer needed */
    114    close(fd);
    115
    116}
    117
    118/**
    119 * Tests that the nested socket implementation of guac_socket properly
    120 * implements writing of instructions. A child process is forked to write a
    121 * series of instructions which are read and verified by the parent process.
    122 */
    123void test_socket__nested_send_instruction() {
    124
    125    int fd[2];
    126
    127    /* Create pipe */
    128    CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
    129
    130    int read_fd = fd[0];
    131    int write_fd = fd[1];
    132
    133    /* Fork into writer process (child) and reader process (parent) */
    134    int childpid;
    135    CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1);
    136
    137    /* Attempt to write a series of instructions within the child process */
    138    if (childpid == 0) {
    139        close(read_fd);
    140        write_instructions(write_fd);
    141        exit(0);
    142    }
    143
    144    /* Read and verify the expected instructions within the parent process */
    145    close(write_fd);
    146    read_expected_instructions(read_fd);
    147 
    148}
    149