]> git.proxmox.com Git - mirror_ovs.git/blame - lib/smap.c
flow: Fix buffer overread in flow_hash_symmetric_l3l4().
[mirror_ovs.git] / lib / smap.c
CommitLineData
f99f67bd 1/* Copyright (c) 2012, 2014, 2015, 2016 Nicira, Inc.
79f1cbe9
EJ
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License. */
14
15#include <config.h>
16#include "smap.h"
17
edefaa2e
YT
18#include <strings.h>
19
79f1cbe9 20#include "hash.h"
ee89ea7b 21#include "openvswitch/json.h"
719a3d25 22#include "packets.h"
d65467f1 23#include "uuid.h"
79f1cbe9
EJ
24
25static struct smap_node *smap_add__(struct smap *, char *, void *,
26 size_t hash);
27static struct smap_node *smap_find__(const struct smap *, const char *key,
28 size_t key_len, size_t hash);
29static int compare_nodes_by_key(const void *, const void *);
30\f
31/* Public Functions. */
32
33void
34smap_init(struct smap *smap)
35{
36 hmap_init(&smap->map);
37}
38
39void
40smap_destroy(struct smap *smap)
41{
42 if (smap) {
43 smap_clear(smap);
44 hmap_destroy(&smap->map);
45 }
46}
47
48/* Adds 'key' paired with 'value' to 'smap'. It is the caller's responsibility
49 * to avoid duplicate keys if desirable. */
50struct smap_node *
51smap_add(struct smap *smap, const char *key, const char *value)
52{
53 size_t key_len = strlen(key);
54 return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
55 hash_bytes(key, key_len, 0));
56}
57
ff929935
BP
58/* Adds 'key' paired with 'value' to 'smap'. Takes ownership of 'key' and
59 * 'value' (which will eventually be freed with free()). It is the caller's
60 * responsibility to avoid duplicate keys if desirable. */
61struct smap_node *
62smap_add_nocopy(struct smap *smap, char *key, char *value)
63{
64 return smap_add__(smap, key, value, hash_bytes(key, strlen(key), 0));
65}
66
79f1cbe9
EJ
67/* Attempts to add 'key' to 'smap' associated with 'value'. If 'key' already
68 * exists in 'smap', does nothing and returns false. Otherwise, performs the
69 * addition and returns true. */
70bool
71smap_add_once(struct smap *smap, const char *key, const char *value)
72{
73 if (!smap_get(smap, key)) {
74 smap_add(smap, key, value);
75 return true;
76 } else {
77 return false;
78 }
79}
80
81/* Adds 'key' paired with a value derived from 'format' (similar to printf).
82 * It is the caller's responsibility to avoid duplicate keys if desirable. */
83void
84smap_add_format(struct smap *smap, const char *key, const char *format, ...)
85{
86 size_t key_len;
87 va_list args;
88 char *value;
89
90 va_start(args, format);
91 value = xvasprintf(format, args);
92 va_end(args);
93
94 key_len = strlen(key);
95 smap_add__(smap, xmemdup0(key, key_len), value,
96 hash_bytes(key, key_len, 0));
97}
98
9835576b
JB
99/* Adds 'key' paired with a string representation of 'addr'. It is the
100 * caller's responsibility to avoid duplicate keys if desirable. */
101void
102smap_add_ipv6(struct smap *smap, const char *key, struct in6_addr *addr)
103{
104 char buf[INET6_ADDRSTRLEN];
719a3d25 105 ipv6_string_mapped(buf, addr);
9835576b
JB
106 smap_add(smap, key, buf);
107}
108
79f1cbe9
EJ
109/* Searches for 'key' in 'smap'. If it does not already exists, adds it.
110 * Otherwise, changes its value to 'value'. */
111void
112smap_replace(struct smap *smap, const char *key, const char *value)
113{
114 size_t key_len = strlen(key);
115 size_t hash = hash_bytes(key, key_len, 0);
116
117 struct smap_node *node;
118
119 node = smap_find__(smap, key, key_len, hash);
120 if (node) {
121 free(node->value);
122 node->value = xstrdup(value);
123 } else {
124 smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash);
125 }
126}
127
128/* If 'key' is in 'smap', removes it. Otherwise does nothing. */
129void
130smap_remove(struct smap *smap, const char *key)
131{
132 struct smap_node *node = smap_get_node(smap, key);
133
134 if (node) {
135 smap_remove_node(smap, node);
136 }
137}
138
139/* Removes 'node' from 'smap'. */
140void
141smap_remove_node(struct smap *smap, struct smap_node *node)
142{
143 hmap_remove(&smap->map, &node->node);
144 free(node->key);
145 free(node->value);
146 free(node);
147}
148
57c8677b
BP
149/* Deletes 'node' from 'smap'.
150 *
151 * If 'keyp' is nonnull, stores the node's key in '*keyp' and transfers
152 * ownership to the caller. Otherwise, frees the node's key. Similarly for
153 * 'valuep' and the node's value. */
154void
155smap_steal(struct smap *smap, struct smap_node *node,
156 char **keyp, char **valuep)
51c82a49 157{
57c8677b
BP
158 if (keyp) {
159 *keyp = node->key;
160 } else {
161 free(node->key);
162 }
163
164 if (valuep) {
165 *valuep = node->value;
166 } else {
167 free(node->value);
168 }
51c82a49
BP
169
170 hmap_remove(&smap->map, &node->node);
171 free(node);
51c82a49
BP
172}
173
79f1cbe9
EJ
174/* Removes all key-value pairs from 'smap'. */
175void
176smap_clear(struct smap *smap)
177{
178 struct smap_node *node, *next;
179
180 SMAP_FOR_EACH_SAFE (node, next, smap) {
181 smap_remove_node(smap, node);
182 }
183}
184
f99f67bd
BP
185/* Returns the value associated with 'key' in 'smap'.
186 * If 'smap' does not contain 'key', returns NULL. */
79f1cbe9
EJ
187const char *
188smap_get(const struct smap *smap, const char *key)
f99f67bd
BP
189{
190 return smap_get_def(smap, key, NULL);
191}
192
193/* Returns the value associated with 'key' in 'smap'.
194 * If 'smap' does not contain 'key', returns 'def'. */
195const char *
196smap_get_def(const struct smap *smap, const char *key, const char *def)
79f1cbe9
EJ
197{
198 struct smap_node *node = smap_get_node(smap, key);
f99f67bd 199 return node ? node->value : def;
79f1cbe9
EJ
200}
201
202/* Returns the node associated with 'key' in 'smap', or NULL. */
203struct smap_node *
204smap_get_node(const struct smap *smap, const char *key)
205{
206 size_t key_len = strlen(key);
207 return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
208}
209
210/* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
211 * If 'key' is not in 'smap', or its value is neither "true" nor "false",
212 * returns 'def'. */
213bool
214smap_get_bool(const struct smap *smap, const char *key, bool def)
215{
f99f67bd 216 const char *value = smap_get_def(smap, key, "");
79f1cbe9
EJ
217 if (def) {
218 return strcasecmp("false", value) != 0;
219 } else {
220 return !strcasecmp("true", value);
221 }
222}
223
224/* Gets the value associated with 'key' in 'smap' and converts it to an int
225 * using atoi(). If 'key' is not in 'smap', returns 'def'. */
226int
227smap_get_int(const struct smap *smap, const char *key, int def)
228{
229 const char *value = smap_get(smap, key);
230
231 return value ? atoi(value) : def;
232}
233
13c1637f
BP
234/* Gets the value associated with 'key' in 'smap' and converts it to an int
235 * using strtoull(). If 'key' is not in 'smap', returns 'def'. */
236unsigned long long int
237smap_get_ullong(const struct smap *smap, const char *key,
238 unsigned long long def)
239{
240 const char *value = smap_get(smap, key);
241
242 return value ? strtoull(value, NULL, 10) : def;
243}
244
d65467f1
BP
245/* Gets the value associated with 'key' in 'smap' and converts it to a UUID
246 * using uuid_from_string(). Returns true if successful, false if 'key' is not
247 * in 'smap' or if 'key' does not have the correct syntax for a UUID. */
248bool
249smap_get_uuid(const struct smap *smap, const char *key, struct uuid *uuid)
250{
f99f67bd 251 return uuid_from_string(uuid, smap_get_def(smap, key, ""));
d65467f1
BP
252}
253
79f1cbe9
EJ
254/* Returns true of there are no elements in 'smap'. */
255bool
256smap_is_empty(const struct smap *smap)
257{
258 return hmap_is_empty(&smap->map);
259}
260
261/* Returns the number of elements in 'smap'. */
262size_t
263smap_count(const struct smap *smap)
264{
265 return hmap_count(&smap->map);
266}
267
268/* Initializes 'dst' as a clone of 'src. */
269void
4512aaa7 270smap_clone(struct smap *dst, const struct smap *src)
79f1cbe9 271{
4512aaa7 272 const struct smap_node *node;
79f1cbe9
EJ
273
274 smap_init(dst);
275 SMAP_FOR_EACH (node, src) {
276 smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
277 node->node.hash);
278 }
279}
280
281/* Returns an array of nodes sorted on key or NULL if 'smap' is empty. The
282 * caller is responsible for freeing this array. */
283const struct smap_node **
284smap_sort(const struct smap *smap)
285{
286 if (smap_is_empty(smap)) {
287 return NULL;
288 } else {
289 const struct smap_node **nodes;
290 struct smap_node *node;
291 size_t i, n;
292
293 n = smap_count(smap);
294 nodes = xmalloc(n * sizeof *nodes);
295 i = 0;
296 SMAP_FOR_EACH (node, smap) {
297 nodes[i++] = node;
298 }
cb22974d 299 ovs_assert(i == n);
79f1cbe9
EJ
300
301 qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
302
303 return nodes;
304 }
305}
cccc1356
BP
306
307/* Adds each of the key-value pairs from 'json' (which must be a JSON object
308 * whose values are strings) to 'smap'.
309 *
310 * The caller must have initialized 'smap'.
311 *
312 * The caller retains ownership of 'json' and everything in it. */
313void
314smap_from_json(struct smap *smap, const struct json *json)
315{
316 const struct shash_node *node;
317
318 SHASH_FOR_EACH (node, json_object(json)) {
319 const struct json *value = node->data;
320 smap_add(smap, node->name, json_string(value));
321 }
322}
323
324/* Returns a JSON object that maps from the keys in 'smap' to their values.
325 *
326 * The caller owns the returned value and must eventually json_destroy() it.
327 *
328 * The caller retains ownership of 'smap' and everything in it. */
329struct json *
330smap_to_json(const struct smap *smap)
331{
332 const struct smap_node *node;
333 struct json *json;
334
335 json = json_object_create();
336 SMAP_FOR_EACH (node, smap) {
337 json_object_put_string(json, node->key, node->value);
338 }
339 return json;
340}
7962b7f0
RB
341
342/* Returns true if the two maps are equal, meaning that they have the same set
343 * of key-value pairs.
344 */
345bool
346smap_equal(const struct smap *smap1, const struct smap *smap2)
347{
348 if (smap_count(smap1) != smap_count(smap2)) {
349 return false;
350 }
351
352 const struct smap_node *node;
353 SMAP_FOR_EACH (node, smap1) {
354 const char *value2 = smap_get(smap2, node->key);
355 if (!value2 || strcmp(node->value, value2)) {
356 return false;
357 }
358 }
359 return true;
360}
79f1cbe9
EJ
361\f
362/* Private Helpers. */
363
364static struct smap_node *
365smap_add__(struct smap *smap, char *key, void *value, size_t hash)
366{
367 struct smap_node *node = xmalloc(sizeof *node);
368 node->key = key;
369 node->value = value;
370 hmap_insert(&smap->map, &node->node, hash);
371 return node;
372}
373
374static struct smap_node *
375smap_find__(const struct smap *smap, const char *key, size_t key_len,
376 size_t hash)
377{
378 struct smap_node *node;
379
380 HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
381 if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
382 return node;
383 }
384 }
385
386 return NULL;
387}
388
389static int
390compare_nodes_by_key(const void *a_, const void *b_)
391{
392 const struct smap_node *const *a = a_;
393 const struct smap_node *const *b = b_;
394 return strcmp((*a)->key, (*b)->key);
395}