/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "config.h" #include "common/list.h" #include "proc.h" #include "proc-map.h" #include #include #include /** * Returns a hash code based on the given connection ID. * * @param str * The string containing the connection ID. * * @return * A reasonably well-distributed hash code for the given string. */ static unsigned int __guacd_client_hash(const char* str) { unsigned int hash_value = 0; int c; /* Apply each character in string to the hash code */ while ((c = *(str++))) hash_value = hash_value * 65599 + c; return hash_value; } /** * Locates the bucket corresponding to the hash code indicated by the given id, * where the hash code is dictated by __guacd_client_hash(). Each bucket is an * instance of guac_common_list. * * @param map * The map to retrieve the hash bucket from. * * @param id * The ID whose hash code determines the bucket being retrieved. * * @return * The bucket corresponding to the hash code for the given ID, represented * by a guac_common_list. */ static guac_common_list* __guacd_proc_find_bucket(guacd_proc_map* map, const char* id) { const int index = __guacd_client_hash(id) % GUACD_PROC_MAP_BUCKETS; return map->__buckets[index]; } /** * Given a bucket of guacd_proc instances, returns the guacd_proc having the * guac_client with the given ID, or NULL if no such client is stored. * * @param bucket * The bucket of guacd_proc instances to search, represented as a * guac_common_list. * * @param id * The ID of the guac_client whose corresponding guacd_proc instance should * be located within the bucket. * * @return * The guac_common_list_element containing the guacd_proc instance * corresponding to the guac_client having the given ID, or NULL of no such * element exists. */ static guac_common_list_element* __guacd_proc_find(guac_common_list* bucket, const char* id) { guac_common_list_element* current = bucket->head; /* Search for matching element within bucket */ while (current != NULL) { /* Check connection ID */ guacd_proc* proc = (guacd_proc*) current->data; if (strcmp(proc->client->connection_id, id) == 0) break; current = current->next; } return current; } guacd_proc_map* guacd_proc_map_alloc() { guacd_proc_map* map = malloc(sizeof(guacd_proc_map)); guac_common_list** current; int i; /* Init all buckets */ current = map->__buckets; for (i=0; iclient->connection_id; guac_common_list* bucket = __guacd_proc_find_bucket(map, identifier); guac_common_list_element* found; /* Retrieve corresponding element, if any */ guac_common_list_lock(bucket); found = __guacd_proc_find(bucket, identifier); /* If no such element, we can add the new client successfully */ if (found == NULL) { guac_common_list_add(bucket, proc); guac_common_list_unlock(bucket); return 0; } /* Otherwise, fail - already exists */ guac_common_list_unlock(bucket); return 1; } guacd_proc* guacd_proc_map_retrieve(guacd_proc_map* map, const char* id) { guacd_proc* proc; guac_common_list* bucket = __guacd_proc_find_bucket(map, id); guac_common_list_element* found; /* Retrieve corresponding element, if any */ guac_common_list_lock(bucket); found = __guacd_proc_find(bucket, id); /* If no such element, fail */ if (found == NULL) { guac_common_list_unlock(bucket); return NULL; } proc = (guacd_proc*) found->data; guac_common_list_unlock(bucket); return proc; } guacd_proc* guacd_proc_map_remove(guacd_proc_map* map, const char* id) { guacd_proc* proc; guac_common_list* bucket = __guacd_proc_find_bucket(map, id); guac_common_list_element* found; /* Retrieve corresponding element, if any */ guac_common_list_lock(bucket); found = __guacd_proc_find(bucket, id); /* If no such element, fail */ if (found == NULL) { guac_common_list_unlock(bucket); return NULL; } proc = (guacd_proc*) found->data; guac_common_list_remove(bucket, found); guac_common_list_unlock(bucket); return proc; }