Coverage Report

Created: 2026-01-09 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/src/guid.c
Line
Count
Source
1
#include <haproxy/guid.h>
2
3
#include <import/cebis_tree.h>
4
#include <haproxy/listener-t.h>
5
#include <haproxy/obj_type.h>
6
#include <haproxy/proxy.h>
7
#include <haproxy/server-t.h>
8
#include <haproxy/tools.h>
9
#include <haproxy/thread.h>
10
11
/* GUID global tree */
12
struct ceb_root *guid_tree = NULL;
13
__decl_thread(HA_RWLOCK_T guid_lock);
14
15
/* note: touched under the guid_lock */
16
static int _guid_count = 0;
17
18
/* Initialize <guid> members. */
19
void guid_init(struct guid_node *guid)
20
0
{
21
0
  memset(guid, 0, sizeof(*guid));
22
0
}
23
24
/* Insert <objt> into GUID global tree with key <uid>. Must only be called on
25
 * thread isolation. On failure, <errmsg> will be allocated with an error
26
 * description. Caller is responsible to free it.
27
 *
28
 * Returns 0 on success else non-zero.
29
 */
30
int guid_insert(enum obj_type *objt, const char *uid, char **errmsg)
31
0
{
32
0
  struct guid_node *guid = NULL;
33
0
  struct guid_node *dup;
34
0
  char *dup_name = NULL;
35
36
0
  if (!guid_is_valid_fmt(uid, errmsg))
37
0
    goto err;
38
39
0
  switch (obj_type(objt)) {
40
0
  case OBJ_TYPE_PROXY:
41
0
    guid = &__objt_proxy(objt)->guid;
42
0
    break;
43
44
0
  case OBJ_TYPE_LISTENER:
45
0
    guid = &__objt_listener(objt)->guid;
46
0
    break;
47
48
0
  case OBJ_TYPE_SERVER:
49
0
    guid = &__objt_server(objt)->guid;
50
0
    break;
51
52
0
  default:
53
    /* No guid support for this objtype. */
54
0
    ABORT_NOW();
55
0
    return 0;
56
0
  }
57
58
0
  guid->key = strdup(uid);
59
0
  if (!guid->key) {
60
0
    memprintf(errmsg, "key alloc failure");
61
0
    goto err;
62
0
  }
63
64
0
  HA_RWLOCK_WRLOCK(GUID_LOCK, &guid_lock);
65
0
  dup = cebuis_item_insert(&guid_tree, node, key, guid);
66
0
  if (dup != guid) {
67
0
    HA_RWLOCK_WRUNLOCK(GUID_LOCK, &guid_lock);
68
0
    dup_name = guid_name(dup);
69
0
    memprintf(errmsg, "duplicate entry with %s", dup_name);
70
0
    goto err;
71
0
  }
72
0
  _guid_count += 1;
73
0
  HA_RWLOCK_WRUNLOCK(GUID_LOCK, &guid_lock);
74
75
0
  guid->obj_type = objt;
76
77
0
  return 0;
78
79
0
 err:
80
0
  if (guid)
81
0
    ha_free(&guid->key);
82
0
  ha_free(&dup_name);
83
0
  return 1;
84
0
}
85
86
/* Remove <guid> node from GUID global tree. Must only be called on thread
87
 * isolation. Safe to call even if node is not currently stored.
88
 */
89
void guid_remove(struct guid_node *guid)
90
0
{
91
0
  HA_RWLOCK_WRLOCK(GUID_LOCK, &guid_lock);
92
0
  if (guid->key)
93
0
    _guid_count--;
94
0
  cebuis_item_delete(&guid_tree, node, key, guid);
95
0
  ha_free(&guid->key);
96
0
  HA_RWLOCK_WRUNLOCK(GUID_LOCK, &guid_lock);
97
0
}
98
99
/* Retrieve an instance from GUID global tree with key <uid>.
100
 *
101
 * Returns the GUID instance or NULL if key not found.
102
 */
103
struct guid_node *guid_lookup(const char *uid)
104
0
{
105
0
  struct guid_node *guid = NULL;
106
107
  /* For now, guid_lookup() is only used during startup in single-thread
108
   * mode. If this is not the case anymore, GUID tree access must be
109
   * protected with the read-write lock.
110
   */
111
0
  BUG_ON(!(global.mode & MODE_STARTING));
112
113
0
  guid = cebuis_item_lookup(&guid_tree, node, key, uid, struct guid_node);
114
0
  return guid;
115
0
}
116
117
/* Returns a boolean checking if <uid> respects GUID format. If <errmsg> is not
118
 * NULL, it will be allocated with an error description in case of invalid
119
 * format.
120
 */
121
int guid_is_valid_fmt(const char *uid, char **errmsg)
122
0
{
123
0
  const size_t len = strlen(uid);
124
0
  const char *c;
125
126
0
  if (!len || len > GUID_MAX_LEN) {
127
0
    memprintf(errmsg, "invalid length");
128
0
    return 0;
129
0
  }
130
131
0
  c = invalid_char(uid);
132
0
  if (c) {
133
0
    memprintf(errmsg, "invalid character '%c'", c[0]);
134
0
    return 0;
135
0
  }
136
137
0
  return 1;
138
0
}
139
140
/* Generate a user-friendly description for the instance attached via <guid>
141
 * node. The string is dynamically allocated and the caller is responsible to
142
 * free it.
143
 *
144
 * Returns a pointer to the dynamically allocated message.
145
 */
146
char *guid_name(const struct guid_node *guid)
147
0
{
148
0
  char *msg = NULL;
149
0
  struct proxy *px;
150
0
  struct listener *l;
151
0
  struct server *srv;
152
153
0
  switch (obj_type(guid->obj_type)) {
154
0
  case OBJ_TYPE_PROXY:
155
0
    px = __objt_proxy(guid->obj_type);
156
0
    return memprintf(&msg, "%s %s", proxy_cap_str(px->cap), px->id);
157
158
0
  case OBJ_TYPE_LISTENER:
159
0
    l = __objt_listener(guid->obj_type);
160
0
    return memprintf(&msg, "listener %s (%s:%d)",
161
0
                     l->bind_conf->frontend->id,
162
0
                     l->bind_conf->file, l->bind_conf->line);
163
164
0
  case OBJ_TYPE_SERVER:
165
0
    srv = __objt_server(guid->obj_type);
166
0
    return memprintf(&msg, "server %s/%s", srv->proxy->id, srv->id);
167
168
0
  default:
169
0
    break;
170
0
  }
171
172
0
  return NULL;
173
0
}
174
175
/* returns the number of guid inserted in guid_tree */
176
int guid_count(void)
177
0
{
178
0
  int count;
179
180
0
  HA_RWLOCK_WRLOCK(GUID_LOCK, &guid_lock);
181
0
  count = _guid_count;
182
0
  HA_RWLOCK_WRUNLOCK(GUID_LOCK, &guid_lock);
183
0
  return count;
184
0
}