cscg24-guacamole

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

proc-map.c (7267B)


      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 "common/list.h"
     22#include "proc.h"
     23#include "proc-map.h"
     24
     25#include <guacamole/client.h>
     26#include <guacamole/mem.h>
     27
     28#include <stdlib.h>
     29#include <string.h>
     30
     31/**
     32 * A value to be stored in the buckets, containing the guacd proc itself,
     33 * as well as a link to the element in the list of all guacd processes.
     34 */
     35typedef struct guacd_proc_map_entry {
     36
     37    /**
     38     * The guacd process itself.
     39     */
     40    guacd_proc* proc;
     41
     42    /**
     43     * A pointer to the corresponding entry in the list of all processes.
     44     */
     45    guac_common_list_element* element;
     46
     47} guacd_proc_map_entry;
     48
     49/**
     50 * Returns a hash code based on the given connection ID.
     51 *
     52 * @param str
     53 *     The string containing the connection ID.
     54 *
     55 * @return
     56 *     A reasonably well-distributed hash code for the given string.
     57 */
     58static unsigned int __guacd_client_hash(const char* str) {
     59
     60    unsigned int hash_value = 0;
     61    int c;
     62
     63    /* Apply each character in string to the hash code */
     64    while ((c = *(str++)))
     65        hash_value = hash_value * 65599 + c;
     66
     67    return hash_value;
     68
     69}
     70
     71/**
     72 * Locates the bucket corresponding to the hash code indicated by the given id,
     73 * where the hash code is dictated by __guacd_client_hash().  Each bucket is an
     74 * instance of guac_common_list.
     75 *
     76 * @param map
     77 *     The map to retrieve the hash bucket from.
     78 *
     79 * @param id
     80 *     The ID whose hash code determines the bucket being retrieved.
     81 *
     82 * @return
     83 *     The bucket corresponding to the hash code for the given ID, represented
     84 *     by a guac_common_list.
     85 */
     86static guac_common_list* __guacd_proc_find_bucket(guacd_proc_map* map,
     87        const char* id) {
     88
     89    const int index = __guacd_client_hash(id) % GUACD_PROC_MAP_BUCKETS;
     90    return map->__buckets[index];
     91
     92}
     93
     94/**
     95 * Given a bucket of guacd_proc instances, returns the guacd_proc having the
     96 * guac_client with the given ID, or NULL if no such client is stored.
     97 *
     98 * @param bucket
     99 *     The bucket of guacd_proc instances to search, represented as a
    100 *     guac_common_list.
    101 *
    102 * @param id
    103 *     The ID of the guac_client whose corresponding guacd_proc instance should
    104 *     be located within the bucket.
    105 *
    106 * @return
    107 *     The guac_common_list_element containing the guacd_proc instance
    108 *     corresponding to the guac_client having the given ID, or NULL of no such
    109 *     element exists.
    110 */
    111static guac_common_list_element* __guacd_proc_find(guac_common_list* bucket,
    112        const char* id) {
    113
    114    guac_common_list_element* current = bucket->head;
    115
    116    /* Search for matching element within bucket */
    117    while (current != NULL) {
    118
    119        /* Check connection ID */
    120        guacd_proc* proc = ((guacd_proc_map_entry*) current->data)->proc;
    121        if (strcmp(proc->client->connection_id, id) == 0)
    122            break;
    123
    124        current = current->next;
    125    }
    126
    127    return current;
    128
    129}
    130
    131guacd_proc_map* guacd_proc_map_alloc() {
    132
    133    guacd_proc_map* map = guac_mem_alloc(sizeof(guacd_proc_map));
    134    map->processes = guac_common_list_alloc();
    135    guac_common_list** current;
    136
    137    int i;
    138
    139    /* Init all buckets */
    140    current = map->__buckets;
    141
    142    for (i=0; i<GUACD_PROC_MAP_BUCKETS; i++) {
    143        *current = guac_common_list_alloc();
    144        current++;
    145    }
    146
    147    return map;
    148
    149}
    150
    151int guacd_proc_map_add(guacd_proc_map* map, guacd_proc* proc) {
    152
    153    const char* identifier = proc->client->connection_id;
    154    guac_common_list* bucket = __guacd_proc_find_bucket(map, identifier);
    155    guac_common_list_element* found;
    156
    157    /* Retrieve corresponding element, if any */
    158    guac_common_list_lock(bucket);
    159    found = __guacd_proc_find(bucket, identifier);
    160
    161    /* If no such element, we can add the new client successfully */
    162    if (found == NULL) {
    163
    164        guacd_proc_map_entry* entry = guac_mem_alloc(sizeof(guacd_proc_map_entry));
    165
    166        guac_common_list_lock(map->processes);
    167        entry->element = guac_common_list_add(map->processes, proc);
    168        guac_common_list_unlock(map->processes);
    169
    170        entry->proc = proc;
    171
    172        guac_common_list_add(bucket, entry);
    173        guac_common_list_unlock(bucket);
    174
    175        return 0;
    176    }
    177
    178    /* Otherwise, fail - already exists */
    179    guac_common_list_unlock(bucket);
    180    return 1;
    181
    182}
    183
    184guacd_proc* guacd_proc_map_retrieve(guacd_proc_map* map, const char* id) {
    185
    186    guacd_proc* proc;
    187
    188    guac_common_list* bucket = __guacd_proc_find_bucket(map, id);
    189    guac_common_list_element* found;
    190
    191    /* Retrieve corresponding element, if any */
    192    guac_common_list_lock(bucket);
    193    found = __guacd_proc_find(bucket, id);
    194
    195    /* If no such element, fail */
    196    if (found == NULL) {
    197        guac_common_list_unlock(bucket);
    198        return NULL;
    199    }
    200
    201    proc = ((guacd_proc_map_entry*) found->data)->proc;
    202
    203    guac_common_list_unlock(bucket);
    204    return proc;
    205
    206}
    207
    208guacd_proc* guacd_proc_map_remove(guacd_proc_map* map, const char* id) {
    209
    210    guacd_proc* proc;
    211
    212    guac_common_list* bucket = __guacd_proc_find_bucket(map, id);
    213    guac_common_list_element* found;
    214
    215    /* Retrieve corresponding element, if any */
    216    guac_common_list_lock(bucket);
    217    found = __guacd_proc_find(bucket, id);
    218
    219    /* If no such element, fail */
    220    if (found == NULL) {
    221        guac_common_list_unlock(bucket);
    222        return NULL;
    223    }
    224
    225    guacd_proc_map_entry* entry = (guacd_proc_map_entry*) found->data;
    226
    227    /* Find and remove the key from the process list */
    228    guac_common_list_lock(map->processes);
    229    guac_common_list_remove(map->processes, entry->element);
    230    guac_common_list_unlock(map->processes);
    231
    232    proc = entry->proc;
    233    guac_common_list_remove(bucket, found);
    234
    235    free (entry);
    236
    237    guac_common_list_unlock(bucket);
    238    return proc;
    239
    240}
    241
    242void guacd_proc_map_foreach(guacd_proc_map* map,
    243        guacd_proc_map_foreach_callback* callback, void* data) {
    244
    245    guac_common_list* list = map->processes;
    246
    247    guac_common_list_lock(list);
    248
    249    /* Invoke the callback for every element in the list */
    250    guac_common_list_element* element;
    251    for (element = list->head; element != NULL; element = element->next)
    252        callback((guacd_proc*) element->data, data);
    253
    254    guac_common_list_unlock(list);
    255
    256}
    257
    258void guacd_proc_map_free(guacd_proc_map* map) {
    259
    260    /* Free the list of all processes */
    261    guac_common_list_free(map->processes, NULL);
    262
    263    /* Free each bucket */
    264    guac_common_list** buckets = map->__buckets;
    265    int i;
    266    for (i = 0; i < GUACD_PROC_MAP_BUCKETS; i++) {
    267        guac_common_list_free(*(buckets + i), free);
    268    }
    269
    270}
    271