summaryrefslogtreecommitdiffstats
path: root/src/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map.c')
-rw-r--r--src/map.c100
1 files changed, 83 insertions, 17 deletions
diff --git a/src/map.c b/src/map.c
index 387dfbf..13155aa 100644
--- a/src/map.c
+++ b/src/map.c
@@ -19,6 +19,7 @@
#include "map.h"
#include "portmap.h"
+/* The singleton for the cache. */
struct {
struct domain {
char *name;
@@ -27,7 +28,7 @@ struct {
time_t last_changed;
struct entry {
struct entry *prev, *next;
- char *id, **visited_ids;
+ char *id, **related_ids;
char *key;
unsigned int key_len;
char *value;
@@ -121,6 +122,8 @@ map_data_find_map_entry_id(struct plugin_state *state,
return NULL;
}
+/* Handlers for the list of related IDs. On this side we actually store them
+ * as one contiguous chunk of memory. */
static PRBool
map_id_in_id_list(const char *id, char **id_list)
{
@@ -133,39 +136,60 @@ map_id_in_id_list(const char *id, char **id_list)
return FALSE;
}
+/* Duplicate a passed-in list of strings. The result is stored in one chunk of
+ * memory: pointers first, then the individual strings. */
static char **
map_id_dup_id_list(const char **in_id_list)
{
int i, l;
char **ret, *s;
+ /* Handle the NULL case. */
+ if (in_id_list == NULL) {
+ return NULL;
+ }
+ /* Count the amount of space needed for the strings. */
for (i = 0, l = 0; (in_id_list[i] != NULL); i++) {
l += (strlen(in_id_list[i]) + 1);
}
+ /* No strings = no list. */
if (i == 0) {
return NULL;
}
+ /* Allocate space for the array of pointers (with NULL terminator) and
+ * then the string data. */
ret = malloc((i + 1) * sizeof(char *) + l);
if (ret != NULL) {
+ /* Figure out where the string data will start. */
s = (char *) &ret[i + 1];
for (i = 0; (in_id_list[i] != NULL); i++) {
+ /* Set the address of this string, copy the data
+ * around, and then prepare the address of the next
+ * string. */
ret[i] = s;
strcpy(s, in_id_list[i]);
s += (strlen(s) + 1);
}
+ /* NULL-terminate the array. */
ret[i] = NULL;
}
return ret;
}
+/* Free the list -- since it's one chunk of memory, we shouldn't try anything
+ * complicated. */
static void
map_id_free_id_list(char **id_list)
{
free(id_list);
}
+/* Iterate through every entry in every map, calling the callback if "all" is
+ * true, or if "id" is not NULL and matches the entry's ID, or if the
+ * "related_id" is not NULL and in the list of related IDs. If the callback
+ * returns FALSE, then we abort and return FALSE, otherwise we return TRUE. */
static PRBool
map_data_foreach_entry(struct plugin_state *state,
- PRBool all, const char *id, const char *visited_id,
+ PRBool all, const char *id, const char *related_id,
PRBool (*fn)(const char *domain, const char *map,
const char *key, unsigned int key_len,
const char *value, unsigned int value_len,
@@ -186,9 +210,9 @@ map_data_foreach_entry(struct plugin_state *state,
if (all ||
((id != NULL) &&
(strcmp(id, entry->id) == 0)) ||
- ((visited_id != NULL) &&
- (map_id_in_id_list(visited_id,
- entry->visited_ids)))) {
+ ((related_id != NULL) &&
+ (map_id_in_id_list(related_id,
+ entry->related_ids)))) {
if (!(*fn)(domain->name, map->name,
entry->key,
entry->key_len,
@@ -204,6 +228,7 @@ map_data_foreach_entry(struct plugin_state *state,
return TRUE;
}
+/* Iterate over every entry which matches the corresponding ID. */
PRBool
map_data_foreach_entry_id(struct plugin_state *state, const char *id,
PRBool (*fn)(const char *domain, const char *map,
@@ -217,9 +242,10 @@ map_data_foreach_entry_id(struct plugin_state *state, const char *id,
return map_data_foreach_entry(state, FALSE, id, NULL, fn, cbdata);
}
+/* Iterate over every entry which lists the ID as a related ID. */
PRBool
-map_data_foreach_entry_visited_id(struct plugin_state *state,
- const char *visited_id,
+map_data_foreach_entry_related_id(struct plugin_state *state,
+ const char *related_id,
PRBool (*fn)(const char *domain,
const char *map,
const char *key,
@@ -229,10 +255,42 @@ map_data_foreach_entry_visited_id(struct plugin_state *state,
const char *id, void *cbdata),
void *cbdata)
{
- return map_data_foreach_entry(state, FALSE, NULL, visited_id,
+ return map_data_foreach_entry(state, FALSE, NULL, related_id,
fn, cbdata);
}
+/* Iterate over all maps, calling the callback with information about the map
+ * and whatever the caller originally told us to keep track of when the map was
+ * first set up. */
+PRBool
+map_data_foreach_map(struct plugin_state *state, const char *domain_name,
+ PRBool (*fn)(const char *domain,
+ const char *map,
+ void *backend_data,
+ void *cbdata),
+ void *cbdata)
+{
+ int i, j;
+ struct domain *domain;
+ struct map *map;
+ struct entry *entry;
+ for (i = 0; i < map_data.n_domains; i++) {
+ domain = &map_data.domains[i];
+ if ((domain_name != NULL) &&
+ (strcmp(domain->name, domain_name) != 0)) {
+ continue;
+ }
+ for (j = 0; j < domain->n_maps; j++) {
+ map = &domain->maps[j];
+ if (!(*fn)(domain->name, map->name, map->backend_data,
+ cbdata)) {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
/* 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. */
@@ -504,6 +562,8 @@ map_data_set_map(struct plugin_state *state,
}
}
} else {
+ /* There's already a map there, we just need to update the
+ * data we're keeping track of for the backend. */
if (map->free_backend_data != NULL) {
map->free_backend_data(map->backend_data);
}
@@ -531,6 +591,7 @@ map_data_unset_map_entry(struct plugin_state *state,
if (map->entries == entry) {
map->entries = next;
}
+ map_id_free_id_list(entry->related_ids);
free(entry->id);
free(entry->key);
free(entry->value);
@@ -538,6 +599,7 @@ map_data_unset_map_entry(struct plugin_state *state,
}
}
+/* Remove the entry from the map which matches the passed-in key. */
void
map_data_unset_entry_key(struct plugin_state *state,
const char *domain_name,
@@ -553,6 +615,7 @@ map_data_unset_entry_key(struct plugin_state *state,
map->last_changed = time(NULL);
}
+/* Remove the entry from the map which matches the passed-in ID. */
void
map_data_unset_entry_id(struct plugin_state *state,
const char *domain_name,
@@ -573,7 +636,7 @@ map_data_set_entry(struct plugin_state *state,
const char *domain_name,
const char *map_name,
const char *id,
- const char **visited_ids,
+ const char **related_ids,
unsigned int key_len,
char *key,
unsigned int value_len,
@@ -591,26 +654,29 @@ map_data_set_entry(struct plugin_state *state,
if (map != NULL) {
entry = map_data_find_map_entry_id(state, map, id);
if (entry != NULL) {
+ /* There's already an entry with this ID, so let's
+ * replace its key and value. */
free(entry->key);
- free(entry->value);
- entry->key = key;
+ entry->key = xmemdup(key, key_len);
entry->key_len = key_len;
- entry->value = value;
+ free(entry->value);
+ entry->value = xmemdup(value, value_len);
entry->value_len = value_len;
free(entry->id);
entry->id = strdup(id);
- map_id_free_id_list(entry->visited_ids);
- entry->visited_ids = map_id_dup_id_list(visited_ids);
+ map_id_free_id_list(entry->related_ids);
+ entry->related_ids = map_id_dup_id_list(related_ids);
} else {
+ /* There's no entry with this ID, so create one. */
entry = malloc(sizeof(*entry));
if (entry != NULL) {
memset(entry, 0, sizeof(*entry));
- entry->key = key;
+ entry->key = xmemdup(key, key_len);
entry->key_len = key_len;
- entry->value = value;
+ entry->value = xmemdup(value, value_len);
entry->value_len = value_len;
entry->id = strdup(id);
- entry->visited_ids = map_id_dup_id_list(visited_ids);
+ entry->related_ids = map_id_dup_id_list(related_ids);
entry->next = map->entries;
if (map->entries != NULL) {
map->entries->prev = entry;