#ifdef HAVE_CONFIG_H #include "../config.h" #endif #include #include #include #include #include #include #include #include #include #include "backend.h" #include "dispatch.h" #include "map.h" #include "portmap.h" struct { struct domain { char *name; struct map { char *name; time_t last_changed; struct entry { struct entry *prev, *next; char *id; char *key; unsigned int key_len; char *value; unsigned int value_len; } *entries; } *maps; int n_maps; } *domains; int n_domains; } map_data; /* Utility function - find the domain record for the named domain. */ static struct domain * map_data_find_domain(struct plugin_state *state, const char *domain_name) { int i; for (i = 0; i < map_data.n_domains; i++) { if (strcmp(domain_name, map_data.domains[i].name) == 0) { return &map_data.domains[i]; } } return NULL; } /* Utility function - find the map record for the named map in the named * domain. */ static struct map * map_data_find_map(struct plugin_state *state, const char *domain_name, const char *map_name) { int i; struct domain *domain; domain = map_data_find_domain(state, domain_name); if (domain != NULL) { for (i = 0; i < domain->n_maps; i++) { if (strcmp(map_name, domain->maps[i].name) == 0) { return &domain->maps[i]; } } } return NULL; } /* Utility functions - find a specific entry in the named map in the named * domain. */ static struct entry * map_data_find_map_entry(struct plugin_state *state, struct map *map, unsigned int key_len, const char *key) { struct entry *entry; if (map == NULL) { return NULL; } for (entry = map->entries; entry != NULL; entry = entry->next) { if ((entry->key_len == key_len) && (memcmp(entry->key, key, key_len) == 0)) { return entry; } } return NULL; } static struct entry * map_data_find_entry(struct plugin_state *state, const char *domain_name, const char *map_name, unsigned int key_len, const char *key) { return map_data_find_map_entry(state, map_data_find_map(state, domain_name, map_name), key_len, key); } static struct entry * map_data_find_map_entry_id(struct plugin_state *state, struct map *map, const char *id) { struct entry *entry; if (map == NULL) { return NULL; } for (entry = map->entries; entry != NULL; entry = entry->next) { if (strcmp(entry->id, id) == 0) { return entry; } } return NULL; } /* Query function: check if we have a record for the domain. Return that * information in "supported", and return TRUE unless we ran into internal * errors. */ bool_t map_supports_domain(struct plugin_state *state, const char *domain_name, bool_t *supported) { *supported = (map_data_find_domain(state, domain_name) != NULL); return TRUE; } /* Query function: check if we have a record for the map in the domain. Return * that information in "supported", and return TRUE unless we ran into internal * errors. */ bool_t map_supports_map(struct plugin_state *state, const char *domain_name, const char *map_name, bool_t *supported) { *supported = (map_data_find_map(state, domain_name, map_name) != NULL); return TRUE; } /* Query function: return an indication of the map's age. Should never * decrease. */ bool_t map_order(struct plugin_state *state, const char *domain_name, const char *map_name, unsigned int *order) { struct map *map; map = map_data_find_map(state, domain_name, map_name); if (map != NULL) { *order = map->last_changed & 0xffffffff; return TRUE; } else { return FALSE; } } /* Query function: return the entry value which matches the key. Return TRUE * if we can find a value which corresponds to the key. */ bool_t map_match(struct plugin_state *state, const char *domain_name, const char *map_name, unsigned int key_len, char *key, unsigned int *value_len, char **value) { struct entry *entry; entry = map_data_find_entry(state, domain_name, map_name, key_len, key); if (entry == NULL) { return FALSE; } *value_len = entry->value_len; *value = entry->value; return TRUE; } /* Query function: return the first entry's key and value for a map. Return * FALSE if there's no domain or map. */ bool_t map_first(struct plugin_state *state, const char *domain_name, const char *map_name, unsigned int *first_key_len, char **first_key, unsigned int *first_value_len, char **first_value) { struct map *map; struct entry *entry; map = map_data_find_map(state, domain_name, map_name); if (map == NULL) { return FALSE; } entry = map->entries; if (entry == NULL) { return FALSE; } *first_key_len = entry->key_len; *first_key = entry->key; *first_value_len = entry->value_len; *first_value = entry->value; return TRUE; } /* Query function: return the successor entry's key and value for a map. * Return FALSE if there's no domain or map, or if the predecessor was the last * key in the map. */ bool_t map_next(struct plugin_state *state, const char *domain_name, const char *map_name, unsigned int prev_len, const char *prev, unsigned int *next_key_len, char **next_key, unsigned int *next_value_len, char **next_value) { struct entry *entry; entry = map_data_find_entry(state, domain_name, map_name, prev_len, prev); if ((entry == NULL) || (entry->next == NULL)) { return FALSE; } *next_key_len = entry->next->key_len; *next_key = entry->next->key; *next_value_len = entry->next->value_len; *next_value = entry->next->value; return TRUE; } /* Remove all of the entries in a map. */ static void map_data_clear_map_map(struct plugin_state *state, struct map *map) { struct entry *entry, *next; /* Clear the entries list. */ if (map != NULL) { for (entry = map->entries; entry != NULL; entry = next) { next = entry->next; free(entry->id); entry->key_len = 0; free(entry->key); entry->value_len = 0; free(entry->value); free(entry); } map->entries = NULL; } } void map_data_clear_map(struct plugin_state *state, const char *domain_name, const char *map_name) { map_data_clear_map_map(state, map_data_find_map(state, domain_name, map_name)); } /* Remove a map from the configuration, removing its domain record if the map * was the only one that the domain contained. */ void map_data_unset_map(struct plugin_state *state, const char *domain_name, const char *map_name) { struct domain *domain; struct map *map; int i; /* Check that we have a domain record that matches. */ domain = map_data_find_domain(state, domain_name); if (domain == NULL) { return; } /* Locate the map, remove it from the array of maps. */ memset(&map, 0, sizeof(map)); for (i = 0; i < domain->n_maps; i++) { if (strcmp(domain->maps[i].name, map_name) == 0) { map = &domain->maps[i]; /* Free the contents. */ free(map->name); map_data_clear_map_map(state, map); /* Close the hole in the array. */ domain->n_maps--; if (i != domain->n_maps) { memcpy(&domain->maps[i], &domain->maps[i + 1], sizeof(map) * (domain->n_maps - i)); } break; } } /* If the domain now contains no maps, remove it, too .*/ if (domain->n_maps == 0) { /* Locate the domain, remove it from the array of domains. */ for (i = 0; i < map_data.n_domains; i++) { if (strcmp(map_data.domains[i].name, domain_name) == 0) { domain = &map_data.domains[i]; /* Free the components. */ free(domain->name); free(domain->maps); /* Fill in the hole in the domains array. */ map_data.n_domains--; if (i != map_data.n_domains) { memcpy(&map_data.domains[i], &map_data.domains[i + 1], sizeof(*domain) * (map_data.n_domains - i)); } break; } } } } /* Add a map structure, adding a domain for it if necessary. */ void map_data_set_map(struct plugin_state *state, const char *domain_name, const char *map_name) { struct domain *domain, *domains; struct map *map, *maps; int i; /* Locate the domain for this map. */ domain = NULL; for (i = 0; i < map_data.n_domains; i++) { if (strcmp(map_data.domains[i].name, domain_name) == 0) { domain = &map_data.domains[i]; break; } } /* If we have to, then add to the domain array. */ if (domain == NULL) { /* Allocate space. */ domains = malloc(sizeof(*domain) * (map_data.n_domains + 1)); if (domains != NULL) { /* Populate the new domain. */ domain = &domains[map_data.n_domains]; memset(domain, 0, sizeof(*domain)); domain->name = strdup(domain_name); if (domain->name != NULL) { /* Copy in existing data. */ memcpy(domains, map_data.domains, sizeof(*domain) * map_data.n_domains); /* Switcheroo. */ free(map_data.domains); map_data.domains = domains; map_data.n_domains++; } else { free(domains); /* XXX */ return; } } } /* Check if the map's already been defined in the domain. */ map = NULL; for (i = 0; i < domain->n_maps; i++) { if (strcmp(domain->maps[i].name, map_name) == 0) { map = &domain->maps[i]; break; } } /* We need to either create a new map entry or mess with an old one. */ if (map == NULL) { /* Allocate space. */ maps = malloc(sizeof(*map) * (domain->n_maps + 1)); if (maps != NULL) { /* Populate the new map. */ map = &maps[domain->n_maps]; memset(map, 0, sizeof(*map)); map->name = strdup(map_name); if (map->name != NULL) { /* Copy in existing data. */ memcpy(maps, domain->maps, sizeof(*map) * domain->n_maps); /* Switcheroo. */ free(domain->maps); domain->maps = maps; domain->n_maps++; } else { free(maps); /* XXX */ return; } } } } /* Remove an entry from a map. */ static void map_data_unset_map_entry(struct plugin_state *state, struct map *map, struct entry *entry) { struct entry *prev, *next; if ((map != NULL) && (entry != NULL)) { prev = entry->prev; next = entry->next; if (prev != NULL) { prev->next = next; } if (next != NULL) { next->prev = prev; } if (map->entries == entry) { map->entries = next; } free(entry->id); free(entry->key); free(entry->value); free(entry); } } void map_data_unset_entry_key(struct plugin_state *state, const char *domain_name, const char *map_name, unsigned int key_len, const char *key) { struct map *map; struct entry *entry; map = map_data_find_map(state, domain_name, map_name); entry = map_data_find_map_entry(state, map, key_len, key); map_data_unset_map_entry(state, map, entry); map->last_changed = time(NULL); } void map_data_unset_entry_id(struct plugin_state *state, const char *domain_name, const char *map_name, const char *id) { struct map *map; struct entry *entry; map = map_data_find_map(state, domain_name, map_name); entry = map_data_find_map_entry_id(state, map, id); map_data_unset_map_entry(state, map, entry); map->last_changed = time(NULL); } /* Add an entry to a map. */ void map_data_set_entry(struct plugin_state *state, const char *domain_name, const char *map_name, const char *id, unsigned int key_len, char *key, unsigned int value_len, char *value) { struct map *map; struct entry *entry; map = map_data_find_map(state, domain_name, map_name); if (map != NULL) { entry = map_data_find_map_entry_id(state, map, id); if (entry != NULL) { free(entry->key); free(entry->value); entry->key = key; entry->key_len = key_len; entry->value = value; entry->value_len = value_len; } else { entry = malloc(sizeof(*entry)); if (entry != NULL) { memset(entry, 0, sizeof(*entry)); entry->id = strdup(id); if (entry->id != NULL) { entry->key = key; entry->key_len = key_len; entry->value = value; entry->value_len = value_len; entry->next = map->entries; if (map->entries != NULL) { map->entries->prev = entry; } map->entries = entry; } else { /* XXX */ } } else { /* XXX */ } } } map->last_changed = time(NULL); } void map_init(struct plugin_state *state) { backend_init(state); }