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 | } |