diff options
Diffstat (limited to 'src/guid.c')
-rw-r--r-- | src/guid.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/guid.c b/src/guid.c new file mode 100644 index 0000000..f1365b6 --- /dev/null +++ b/src/guid.c @@ -0,0 +1,161 @@ +#include <haproxy/guid.h> + +#include <import/ebistree.h> +#include <haproxy/listener-t.h> +#include <haproxy/obj_type.h> +#include <haproxy/proxy.h> +#include <haproxy/server-t.h> +#include <haproxy/tools.h> + +/* GUID global tree */ +struct eb_root guid_tree = EB_ROOT_UNIQUE; + +/* Initialize <guid> members. */ +void guid_init(struct guid_node *guid) +{ + guid->node.key = NULL; + guid->node.node.leaf_p = NULL; +} + +/* Insert <objt> into GUID global tree with key <uid>. Must only be called on + * thread isolation. On failure, <errmsg> will be allocated with an error + * description. Caller is responsible to free it. + * + * Returns 0 on success else non-zero. + */ +int guid_insert(enum obj_type *objt, const char *uid, char **errmsg) +{ + struct guid_node *guid = NULL; + struct guid_node *dup; + struct ebpt_node *node; + char *key = NULL; + char *dup_name = NULL; + + if (!guid_is_valid_fmt(uid, errmsg)) + goto err; + + switch (obj_type(objt)) { + case OBJ_TYPE_PROXY: + guid = &__objt_proxy(objt)->guid; + break; + + case OBJ_TYPE_LISTENER: + guid = &__objt_listener(objt)->guid; + break; + + case OBJ_TYPE_SERVER: + guid = &__objt_server(objt)->guid; + break; + + default: + /* No guid support for this objtype. */ + ABORT_NOW(); + return 0; + } + + key = strdup(uid); + if (!key) { + memprintf(errmsg, "key alloc failure"); + goto err; + } + + guid->node.key = key; + node = ebis_insert(&guid_tree, &guid->node); + if (node != &guid->node) { + dup = ebpt_entry(node, struct guid_node, node); + dup_name = guid_name(dup); + memprintf(errmsg, "duplicate entry with %s", dup_name); + goto err; + } + + guid->obj_type = objt; + return 0; + + err: + ha_free(&key); + ha_free(&dup_name); + return 1; +} + +/* Remove <guid> node from GUID global tree. Must only be called on thread + * isolation. Safe to call even if node is not currently stored. + */ +void guid_remove(struct guid_node *guid) +{ + ebpt_delete(&guid->node); + ha_free(&guid->node.key); +} + +/* Retrieve an instance from GUID global tree with key <uid>. + * + * Returns the GUID instance or NULL if key not found. + */ +struct guid_node *guid_lookup(const char *uid) +{ + struct ebpt_node *node = NULL; + struct guid_node *guid = NULL; + + node = ebis_lookup(&guid_tree, uid); + if (node) + guid = ebpt_entry(node, struct guid_node, node); + + return guid; +} + +/* Returns a boolean checking if <uid> respects GUID format. If <errmsg> is not + * NULL, it will be allocated with an error description in case of invalid + * format. + */ +int guid_is_valid_fmt(const char *uid, char **errmsg) +{ + const size_t len = strlen(uid); + const char *c; + + if (!len || len > GUID_MAX_LEN) { + memprintf(errmsg, "invalid length"); + return 0; + } + + c = invalid_char(uid); + if (c) { + memprintf(errmsg, "invalid character '%c'", c[0]); + return 0; + } + + return 1; +} + +/* Generate a user-friendly description for the instance attached via <guid> + * node. The string is dynamically allocated and the caller is responsible to + * free it. + * + * Returns a pointer to the dynamically allocated message. + */ +char *guid_name(const struct guid_node *guid) +{ + char *msg = NULL; + struct proxy *px; + struct listener *l; + struct server *srv; + + switch (obj_type(guid->obj_type)) { + case OBJ_TYPE_PROXY: + px = __objt_proxy(guid->obj_type); + return memprintf(&msg, "%s %s", proxy_cap_str(px->cap), px->id); + + case OBJ_TYPE_LISTENER: + l = __objt_listener(guid->obj_type); + return memprintf(&msg, "listener %s (%s:%d)", + l->bind_conf->frontend->id, + l->bind_conf->file, l->bind_conf->line); + + case OBJ_TYPE_SERVER: + srv = __objt_server(guid->obj_type); + return memprintf(&msg, "server %s/%s", srv->proxy->id, srv->id); + + default: + break; + } + + return NULL; +} |