2024-03-25 10:27:23 +00:00
|
|
|
#include <haproxy/guid.h>
|
|
|
|
|
|
|
|
#include <import/ebistree.h>
|
2024-04-02 08:44:08 +00:00
|
|
|
#include <haproxy/listener-t.h>
|
2024-03-25 10:27:23 +00:00
|
|
|
#include <haproxy/obj_type.h>
|
2024-03-26 14:26:43 +00:00
|
|
|
#include <haproxy/proxy.h>
|
2024-03-26 14:01:35 +00:00
|
|
|
#include <haproxy/server-t.h>
|
2024-03-25 10:27:23 +00:00
|
|
|
#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;
|
2024-04-11 09:05:02 +00:00
|
|
|
char *key = NULL;
|
2024-03-25 10:27:23 +00:00
|
|
|
char *dup_name = NULL;
|
2024-03-27 14:15:19 +00:00
|
|
|
|
2024-04-11 09:10:13 +00:00
|
|
|
if (!guid_is_valid_fmt(uid, errmsg))
|
2024-03-27 14:15:19 +00:00
|
|
|
goto err;
|
2024-03-25 10:27:23 +00:00
|
|
|
|
|
|
|
switch (obj_type(objt)) {
|
2024-03-26 14:26:43 +00:00
|
|
|
case OBJ_TYPE_PROXY:
|
|
|
|
guid = &__objt_proxy(objt)->guid;
|
|
|
|
break;
|
|
|
|
|
2024-04-02 08:44:08 +00:00
|
|
|
case OBJ_TYPE_LISTENER:
|
|
|
|
guid = &__objt_listener(objt)->guid;
|
|
|
|
break;
|
|
|
|
|
2024-03-26 14:01:35 +00:00
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
guid = &__objt_server(objt)->guid;
|
|
|
|
break;
|
|
|
|
|
2024-03-25 10:27:23 +00:00
|
|
|
default:
|
|
|
|
/* No guid support for this objtype. */
|
|
|
|
ABORT_NOW();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-04-11 09:05:02 +00:00
|
|
|
key = strdup(uid);
|
|
|
|
if (!key) {
|
2024-03-25 10:27:23 +00:00
|
|
|
memprintf(errmsg, "key alloc failure");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2024-04-11 09:05:02 +00:00
|
|
|
guid->node.key = key;
|
2024-03-25 10:27:23 +00:00
|
|
|
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:
|
2024-04-11 09:05:02 +00:00
|
|
|
ha_free(&key);
|
2024-03-25 10:27:23 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-04-11 09:10:13 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2024-03-25 10:27:23 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
2024-03-26 14:26:43 +00:00
|
|
|
char *msg = NULL;
|
|
|
|
struct proxy *px;
|
2024-04-02 08:44:08 +00:00
|
|
|
struct listener *l;
|
2024-03-26 14:01:35 +00:00
|
|
|
struct server *srv;
|
2024-03-26 14:26:43 +00:00
|
|
|
|
2024-03-25 10:27:23 +00:00
|
|
|
switch (obj_type(guid->obj_type)) {
|
2024-03-26 14:26:43 +00:00
|
|
|
case OBJ_TYPE_PROXY:
|
|
|
|
px = __objt_proxy(guid->obj_type);
|
|
|
|
return memprintf(&msg, "%s %s", proxy_cap_str(px->cap), px->id);
|
|
|
|
|
2024-04-02 08:44:08 +00:00
|
|
|
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);
|
|
|
|
|
2024-03-26 14:01:35 +00:00
|
|
|
case OBJ_TYPE_SERVER:
|
|
|
|
srv = __objt_server(guid->obj_type);
|
|
|
|
return memprintf(&msg, "server %s/%s", srv->proxy->id, srv->id);
|
|
|
|
|
2024-03-25 10:27:23 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|