cscg24-guacamole

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

socket-tee.c (6613B)


      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
     22#include "guacamole/mem.h"
     23#include "guacamole/socket.h"
     24
     25#include <stdlib.h>
     26
     27/**
     28 * Data specific to the tee implementation of guac_socket.
     29 */
     30typedef struct guac_socket_tee_data {
     31
     32    /**
     33     * The guac_socket to which all socket operations should be delegated.
     34     */
     35    guac_socket* primary;
     36
     37    /**
     38     * The guac_socket to which all write and flush operations should be
     39     * duplicated.
     40     */
     41    guac_socket* secondary;
     42
     43} guac_socket_tee_data;
     44
     45/**
     46 * Callback function which reads only from the primary socket.
     47 *
     48 * @param socket
     49 *     The tee socket to read from.
     50 *
     51 * @param buf
     52 *     The buffer to read data into.
     53 *
     54 * @param count
     55 *     The maximum number of bytes to read into the given buffer.
     56 *
     57 * @return
     58 *     The value returned by guac_socket_read() when invoked on the primary
     59 *     socket with the given parameters.
     60 */
     61static ssize_t __guac_socket_tee_read_handler(guac_socket* socket,
     62        void* buf, size_t count) {
     63
     64    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
     65
     66    /* Delegate read to wrapped socket */
     67    return guac_socket_read(data->primary, buf, count);
     68
     69}
     70
     71/**
     72 * Callback function which writes the given data to both underlying sockets,
     73 * returning only the result from the primary socket.
     74 *
     75 * @param socket
     76 *     The tee socket to write through.
     77 *
     78 * @param buf
     79 *     The buffer of data to write.
     80 *
     81 * @param count
     82 *     The number of bytes in the buffer to be written.
     83 *
     84 * @return
     85 *     The number of bytes written if the write was successful, or -1 if an
     86 *     error occurs.
     87 */
     88static ssize_t __guac_socket_tee_write_handler(guac_socket* socket,
     89        const void* buf, size_t count) {
     90
     91    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
     92
     93    /* Write to secondary socket (ignoring result) */
     94    guac_socket_write(data->secondary, buf, count);
     95
     96    /* Delegate write to wrapped socket */
     97    if (guac_socket_write(data->primary, buf, count))
     98        return -1;
     99
    100    /* All data written successfully */
    101    return count;
    102
    103}
    104
    105/**
    106 * Callback function which flushes both underlying sockets, returning only the
    107 * result from the primary socket.
    108 *
    109 * @param socket
    110 *     The tee socket to flush.
    111 *
    112 * @return
    113 *     The value returned by guac_socket_flush() when invoked on the primary
    114 *     socket.
    115 */
    116static ssize_t __guac_socket_tee_flush_handler(guac_socket* socket) {
    117
    118    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
    119
    120    /* Flush secondary socket (ignoring result) */
    121    guac_socket_flush(data->secondary);
    122
    123    /* Delegate flush to wrapped socket */
    124    return guac_socket_flush(data->primary);
    125
    126}
    127
    128/**
    129 * Callback function which delegates the lock operation to the primary
    130 * socket alone.
    131 *
    132 * @param socket
    133 *     The tee socket on which guac_socket_instruction_begin() was invoked.
    134 */
    135static void __guac_socket_tee_lock_handler(guac_socket* socket) {
    136
    137    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
    138
    139    /* Delegate lock to wrapped sockets */
    140    guac_socket_instruction_begin(data->primary);
    141    guac_socket_instruction_begin(data->secondary);
    142
    143}
    144
    145/**
    146 * Callback function which delegates the unlock operation to the primary
    147 * socket alone.
    148 *
    149 * @param socket
    150 *     The tee socket on which guac_socket_instruction_end() was invoked.
    151 */
    152static void __guac_socket_tee_unlock_handler(guac_socket* socket) {
    153
    154    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
    155
    156    /* Delegate unlock to wrapped sockets */
    157    guac_socket_instruction_end(data->secondary);
    158    guac_socket_instruction_end(data->primary);
    159
    160}
    161
    162/**
    163 * Callback function which delegates the select operation to the primary
    164 * socket alone.
    165 *
    166 * @param socket
    167 *     The tee socket on which guac_socket_select() was invoked.
    168 *
    169 * @param usec_timeout
    170 *     The timeout to specify when invoking guac_socket_select() on the
    171 *     primary socket.
    172 *
    173 * @return
    174 *     The value returned by guac_socket_select() when invoked with the
    175 *     given parameters on the primary socket.
    176 */
    177static int __guac_socket_tee_select_handler(guac_socket* socket,
    178        int usec_timeout) {
    179
    180    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
    181
    182    /* Delegate select to wrapped socket */
    183    return guac_socket_select(data->primary, usec_timeout);
    184
    185}
    186
    187/**
    188 * Callback function which frees all underlying data associated with the
    189 * given tee socket, including both primary and secondary sockets.
    190 *
    191 * @param socket
    192 *     The tee socket being freed.
    193 *
    194 * @return
    195 *     Always zero.
    196 */
    197static int __guac_socket_tee_free_handler(guac_socket* socket) {
    198
    199    guac_socket_tee_data* data = (guac_socket_tee_data*) socket->data;
    200
    201    /* Free underlying sockets */
    202    guac_socket_free(data->primary);
    203    guac_socket_free(data->secondary);
    204
    205    /* Freeing the tee socket always succeeds */
    206    guac_mem_free(data);
    207    return 0;
    208
    209}
    210
    211guac_socket* guac_socket_tee(guac_socket* primary, guac_socket* secondary) {
    212
    213    /* Set up socket to split outout into a file */
    214    guac_socket_tee_data* data = guac_mem_alloc(sizeof(guac_socket_tee_data));
    215    data->primary = primary;
    216    data->secondary = secondary;
    217
    218    /* Associate tee-specific data with new socket */
    219    guac_socket* socket = guac_socket_alloc();
    220    socket->data = data;
    221
    222    /* Assign handlers */
    223    socket->read_handler   = __guac_socket_tee_read_handler;
    224    socket->write_handler  = __guac_socket_tee_write_handler;
    225    socket->select_handler = __guac_socket_tee_select_handler;
    226    socket->flush_handler  = __guac_socket_tee_flush_handler;
    227    socket->lock_handler   = __guac_socket_tee_lock_handler;
    228    socket->unlock_handler = __guac_socket_tee_unlock_handler;
    229    socket->free_handler   = __guac_socket_tee_free_handler;
    230
    231    return socket;
    232
    233}
    234