cscg24-guacamole

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

read.c (4665B)


      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/error.h>
     22#include <guacamole/parser.h>
     23#include <guacamole/protocol.h>
     24#include <guacamole/socket.h>
     25
     26#include <stdlib.h>
     27#include <unistd.h>
     28
     29/**
     30 * Test string which contains exactly four Unicode characters encoded in UTF-8.
     31 * This particular test string uses several characters which encode to multiple
     32 * bytes in UTF-8.
     33 */
     34#define UTF8_4 "\xe7\x8a\xac\xf0\x90\xac\x80z\xc3\xa1"
     35
     36/**
     37 * Writes a series of Guacamole instructions as raw bytes to the given file
     38 * descriptor. The instructions written correspond to the instructions verified
     39 * by read_expected_instructions(). The given file descriptor is automatically
     40 * closed as a result of calling this function.
     41 *
     42 * @param fd
     43 *     The file descriptor to write instructions to.
     44 */
     45static void write_instructions(int fd) {
     46
     47    char test_string[] = "4.test,6.a" UTF8_4 "b,"
     48                         "5.12345,10.a" UTF8_4 UTF8_4 "c;"
     49                         "5.test2,10.hellohello,15.worldworldworld;";
     50
     51    char* current = test_string;
     52    int remaining = sizeof(test_string) - 1;
     53
     54    /* Write all bytes in test string */
     55    while (remaining > 0) {
     56
     57        /* Bail out immediately if write fails (test will fail in parent
     58         * process due to failure to read) */
     59        int written = write(fd, current, remaining);
     60        if (written <= 0)
     61            break;
     62
     63        current += written;
     64        remaining -= written;
     65
     66    }
     67
     68    /* Done writing */
     69    close(fd);
     70
     71}
     72
     73/**
     74 * Reads and parses instructions from the given file descriptor using a
     75 * guac_socket and guac_parser, verifying that those instructions match the
     76 * series of Guacamole instructions expected to be written by
     77 * write_instructions(). The given file descriptor is automatically closed as a
     78 * result of calling this function.
     79 *
     80 * @param fd
     81 *     The file descriptor to read data from.
     82 */
     83static void read_expected_instructions(int fd) {
     84
     85    /* Open guac socket */
     86    guac_socket* socket = guac_socket_open(fd);
     87    CU_ASSERT_PTR_NOT_NULL_FATAL(socket);
     88
     89    /* Allocate parser */
     90    guac_parser* parser = guac_parser_alloc();
     91    CU_ASSERT_PTR_NOT_NULL_FATAL(parser);
     92
     93    /* Read and validate first instruction */
     94    CU_ASSERT_EQUAL_FATAL(guac_parser_read(parser, socket, 1000000), 0);
     95    CU_ASSERT_STRING_EQUAL(parser->opcode, "test");
     96    CU_ASSERT_EQUAL_FATAL(parser->argc, 3);
     97    CU_ASSERT_STRING_EQUAL(parser->argv[0], "a" UTF8_4 "b");
     98    CU_ASSERT_STRING_EQUAL(parser->argv[1], "12345");
     99    CU_ASSERT_STRING_EQUAL(parser->argv[2], "a" UTF8_4 UTF8_4 "c");
    100    
    101    /* Read and validate second instruction */
    102    CU_ASSERT_EQUAL_FATAL(guac_parser_read(parser, socket, 1000000), 0);
    103    CU_ASSERT_STRING_EQUAL(parser->opcode, "test2");
    104    CU_ASSERT_EQUAL_FATAL(parser->argc, 2);
    105    CU_ASSERT_STRING_EQUAL(parser->argv[0], "hellohello");
    106    CU_ASSERT_STRING_EQUAL(parser->argv[1], "worldworldworld");
    107
    108    /* Done */
    109    guac_parser_free(parser);
    110    guac_socket_free(socket);
    111
    112}
    113
    114/**
    115 * Tests that guac_parser_read() correctly reads and parses instructions
    116 * received over a guac_socket. A child process is forked to write a series of
    117 * instructions which are read and verified by the parent process.
    118 */
    119void test_parser__read() {
    120
    121    int fd[2];
    122
    123    /* Create pipe */
    124    CU_ASSERT_EQUAL_FATAL(pipe(fd), 0);
    125
    126    int read_fd = fd[0];
    127    int write_fd = fd[1];
    128
    129    /* Fork into writer process (child) and reader process (parent) */
    130    int childpid;
    131    CU_ASSERT_NOT_EQUAL_FATAL((childpid = fork()), -1);
    132
    133    /* Attempt to write a series of instructions within the child process */
    134    if (childpid == 0) {
    135        close(read_fd);
    136        write_instructions(write_fd);
    137        exit(0);
    138    }
    139
    140    /* Read and verify the expected instructions within the parent process */
    141    close(write_fd);
    142    read_expected_instructions(read_fd);
    143 
    144}
    145