2 * Copyright (c) 2011 Red Hat, Inc.
6 * Author: Jan Friesse (jfriesse@redhat.com)
8 * This software licensed under BSD license, the text of which follows:
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
40 #include <corosync/corotypes.h>
42 #include <qb/qbdefs.h>
43 #include <corosync/list.h>
44 #include <corosync/engine/icmap.h>
46 #define ICMAP_MAX_VALUE_LEN (16*1024)
50 icmap_value_types_t type
;
55 static qb_map_t
*icmap_map
;
60 icmap_notify_fn_t notify_fn
;
64 struct icmap_ro_access_item
{
67 struct list_head list
;
70 DECLARE_LIST_INIT(icmap_ro_access_item_list_head
);
73 * Static functions declarations
77 * Check if key_name is valid icmap key name. Returns 0 on success, and -1 on fail
79 static int icmap_check_key_name(const char *key_name
);
82 * Check that value with given type has correct length value_len. Returns 0 on success,
85 static int icmap_check_value_len(const void *value
, size_t value_len
, icmap_value_types_t type
);
88 * Returns length of value of given type, or 0 for string and binary data type
90 static size_t icmap_get_valuetype_len(icmap_value_types_t type
);
93 * Converts track type of icmap to qb
95 static int32_t icmap_tt_to_qbtt(int32_t track_type
);
98 * Convert track type of qb to icmap
100 static int32_t icmap_qbtt_to_tt(int32_t track_type
);
103 * Checks if item has same value as value with value_len and given type. Returns 0 if not, otherwise !0.
105 static int icmap_item_eq(const struct icmap_item
*item
, const void *value
, size_t value_len
, icmap_value_types_t type
);
108 * Checks if given character is valid in key name. Returns 0 if not, otherwise !0.
110 static int icmap_is_valid_name_char(char c
);
113 * Helper for getting integer and float value with given type for key key_name and store it in value.
115 static cs_error_t
icmap_get_int(
116 const char *key_name
,
118 icmap_value_types_t type
);
121 * Function implementation
123 static int32_t icmap_tt_to_qbtt(int32_t track_type
)
127 if (track_type
& ICMAP_TRACK_DELETE
) {
128 res
|= QB_MAP_NOTIFY_DELETED
;
131 if (track_type
& ICMAP_TRACK_MODIFY
) {
132 res
|= QB_MAP_NOTIFY_REPLACED
;
135 if (track_type
& ICMAP_TRACK_ADD
) {
136 res
|= QB_MAP_NOTIFY_INSERTED
;
139 if (track_type
& ICMAP_TRACK_PREFIX
) {
140 res
|= QB_MAP_NOTIFY_RECURSIVE
;
146 static int32_t icmap_qbtt_to_tt(int32_t track_type
)
150 if (track_type
& QB_MAP_NOTIFY_DELETED
) {
151 res
|= ICMAP_TRACK_DELETE
;
154 if (track_type
& QB_MAP_NOTIFY_REPLACED
) {
155 res
|= ICMAP_TRACK_MODIFY
;
158 if (track_type
& QB_MAP_NOTIFY_INSERTED
) {
159 res
|= ICMAP_TRACK_ADD
;
162 if (track_type
& QB_MAP_NOTIFY_RECURSIVE
) {
163 res
|= ICMAP_TRACK_PREFIX
;
169 static void icmap_map_free_cb(uint32_t event
,
170 char* key
, void* old_value
,
171 void* value
, void* user_data
)
173 struct icmap_item
*item
= (struct icmap_item
*)old_value
;
176 free(item
->key_name
);
181 cs_error_t
icmap_init(void)
185 icmap_map
= qb_trie_create();
186 if (icmap_map
== NULL
)
187 return (CS_ERR_INIT
);
189 err
= qb_map_notify_add(icmap_map
, NULL
, icmap_map_free_cb
, QB_MAP_NOTIFY_FREE
, NULL
);
191 return (qb_to_cs_error(err
));
194 static int icmap_is_valid_name_char(char c
)
196 return ((c
>= 'a' && c
<= 'z') ||
197 (c
>= 'A' && c
<= 'Z') ||
198 (c
>= '0' && c
<= '9') ||
199 c
== '.' || c
== '_' || c
== '-' || c
== '/' || c
== ':');
202 void icmap_convert_name_to_valid_name(char *key_name
)
206 for (i
= 0; i
< strlen(key_name
); i
++) {
207 if (!icmap_is_valid_name_char(key_name
[i
])) {
213 static int icmap_check_key_name(const char *key_name
)
217 if ((strlen(key_name
) < ICMAP_KEYNAME_MINLEN
) || strlen(key_name
) > ICMAP_KEYNAME_MAXLEN
) {
221 for (i
= 0; i
< strlen(key_name
); i
++) {
222 if (!icmap_is_valid_name_char(key_name
[i
])) {
230 static size_t icmap_get_valuetype_len(icmap_value_types_t type
)
235 case ICMAP_VALUETYPE_INT8
: res
= sizeof(int8_t); break;
236 case ICMAP_VALUETYPE_UINT8
: res
= sizeof(uint8_t); break;
237 case ICMAP_VALUETYPE_INT16
: res
= sizeof(int16_t); break;
238 case ICMAP_VALUETYPE_UINT16
: res
= sizeof(uint16_t); break;
239 case ICMAP_VALUETYPE_INT32
: res
= sizeof(int32_t); break;
240 case ICMAP_VALUETYPE_UINT32
: res
= sizeof(uint32_t); break;
241 case ICMAP_VALUETYPE_INT64
: res
= sizeof(int64_t); break;
242 case ICMAP_VALUETYPE_UINT64
: res
= sizeof(uint64_t); break;
243 case ICMAP_VALUETYPE_FLOAT
: res
= sizeof(float); break;
244 case ICMAP_VALUETYPE_DOUBLE
: res
= sizeof(double); break;
245 case ICMAP_VALUETYPE_STRING
:
246 case ICMAP_VALUETYPE_BINARY
:
254 static int icmap_check_value_len(const void *value
, size_t value_len
, icmap_value_types_t type
)
257 if (value_len
> ICMAP_MAX_VALUE_LEN
) {
261 if (type
!= ICMAP_VALUETYPE_STRING
&& type
!= ICMAP_VALUETYPE_BINARY
) {
262 if (icmap_get_valuetype_len(type
) == value_len
) {
269 if (type
== ICMAP_VALUETYPE_STRING
) {
270 if (value_len
> strlen((const char *)value
)) {
280 static int icmap_item_eq(const struct icmap_item
*item
, const void *value
, size_t value_len
, icmap_value_types_t type
)
284 if (item
->type
!= type
) {
288 if (item
->type
== ICMAP_VALUETYPE_STRING
) {
289 ptr_len
= strlen((const char *)value
);
290 if (ptr_len
> value_len
) {
298 if (item
->value_len
== ptr_len
) {
299 return (memcmp(item
->value
, value
, value_len
) == 0);
305 cs_error_t
icmap_set(
306 const char *key_name
,
309 icmap_value_types_t type
)
311 struct icmap_item
*item
;
312 struct icmap_item
*new_item
;
313 size_t new_value_len
;
314 size_t new_item_size
;
316 if (value
== NULL
|| key_name
== NULL
) {
317 return (CS_ERR_INVALID_PARAM
);
320 if (icmap_check_value_len(value
, value_len
, type
) != 0) {
321 return (CS_ERR_INVALID_PARAM
);
324 item
= qb_map_get(icmap_map
, key_name
);
327 * Check that key is really changed
329 if (icmap_item_eq(item
, value
, value_len
, type
)) {
333 if (icmap_check_key_name(key_name
) != 0) {
334 return (CS_ERR_NAME_TOO_LONG
);
338 if (type
== ICMAP_VALUETYPE_BINARY
|| type
== ICMAP_VALUETYPE_STRING
) {
339 if (type
== ICMAP_VALUETYPE_STRING
) {
340 new_value_len
= strlen((const char *)value
);
341 if (new_value_len
> value_len
) {
342 new_value_len
= value_len
;
346 new_value_len
= value_len
;
349 new_value_len
= icmap_get_valuetype_len(type
);
352 new_item_size
= sizeof(struct icmap_item
) + new_value_len
;
353 new_item
= malloc(new_item_size
);
354 if (new_item
== NULL
) {
355 return (CS_ERR_NO_MEMORY
);
357 memset(new_item
, 0, new_item_size
);
360 new_item
->key_name
= strdup(key_name
);
361 if (new_item
->key_name
== NULL
) {
363 return (CS_ERR_NO_MEMORY
);
366 new_item
->key_name
= item
->key_name
;
367 item
->key_name
= NULL
;
370 new_item
->type
= type
;
371 new_item
->value_len
= new_value_len
;
373 memcpy(new_item
->value
, value
, new_value_len
);
375 if (new_item
->type
== ICMAP_VALUETYPE_STRING
) {
376 ((char *)new_item
->value
)[new_value_len
- 1] = 0;
379 qb_map_put(icmap_map
, new_item
->key_name
, new_item
);
384 cs_error_t
icmap_set_int8(const char *key_name
, int8_t value
)
387 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_INT8
));
390 cs_error_t
icmap_set_uint8(const char *key_name
, uint8_t value
)
393 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_UINT8
));
396 cs_error_t
icmap_set_int16(const char *key_name
, int16_t value
)
399 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_INT16
));
402 cs_error_t
icmap_set_uint16(const char *key_name
, uint16_t value
)
405 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_UINT16
));
408 cs_error_t
icmap_set_int32(const char *key_name
, int32_t value
)
411 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_INT32
));
414 cs_error_t
icmap_set_uint32(const char *key_name
, uint32_t value
)
417 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_UINT32
));
420 cs_error_t
icmap_set_int64(const char *key_name
, int64_t value
)
423 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_INT64
));
426 cs_error_t
icmap_set_uint64(const char *key_name
, uint64_t value
)
429 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_UINT64
));
432 cs_error_t
icmap_set_float(const char *key_name
, float value
)
435 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_FLOAT
));
438 cs_error_t
icmap_set_double(const char *key_name
, double value
)
441 return (icmap_set(key_name
, &value
, sizeof(value
), ICMAP_VALUETYPE_DOUBLE
));
444 cs_error_t
icmap_set_string(const char *key_name
, const char *value
)
447 return (icmap_set(key_name
, value
, strlen(value
), ICMAP_VALUETYPE_STRING
));
450 cs_error_t
icmap_delete(const char *key_name
)
452 struct icmap_item
*item
;
454 if (key_name
== NULL
) {
455 return (CS_ERR_INVALID_PARAM
);
458 item
= qb_map_get(icmap_map
, key_name
);
460 return (CS_ERR_NOT_EXIST
);
463 if (qb_map_rm(icmap_map
, item
->key_name
) != QB_TRUE
) {
464 return (CS_ERR_NOT_EXIST
);
470 cs_error_t
icmap_get(
471 const char *key_name
,
474 icmap_value_types_t
*type
)
476 struct icmap_item
*item
;
478 if (key_name
== NULL
) {
479 return (CS_ERR_INVALID_PARAM
);
482 item
= qb_map_get(icmap_map
, key_name
);
484 return (CS_ERR_NOT_EXIST
);
492 if (value_len
!= NULL
) {
493 *value_len
= item
->value_len
;
496 if (value_len
== NULL
|| *value_len
< item
->value_len
) {
497 return (CS_ERR_INVALID_PARAM
);
500 *value_len
= item
->value_len
;
502 memcpy(value
, item
->value
, item
->value_len
);
508 static cs_error_t
icmap_get_int(
509 const char *key_name
,
511 icmap_value_types_t type
)
516 icmap_value_types_t key_type
;
518 key_size
= sizeof(key_value
);
519 memset(key_value
, 0, key_size
);
521 err
= icmap_get(key_name
, key_value
, &key_size
, &key_type
);
525 if (key_type
!= type
) {
526 return (CS_ERR_INVALID_PARAM
);
529 memcpy(value
, key_value
, icmap_get_valuetype_len(key_type
));
534 cs_error_t
icmap_get_int8(const char *key_name
, int8_t *i8
)
537 return (icmap_get_int(key_name
, i8
, ICMAP_VALUETYPE_INT8
));
540 cs_error_t
icmap_get_uint8(const char *key_name
, uint8_t *u8
)
543 return (icmap_get_int(key_name
, u8
, ICMAP_VALUETYPE_UINT8
));
546 cs_error_t
icmap_get_int16(const char *key_name
, int16_t *i16
)
549 return (icmap_get_int(key_name
, i16
, ICMAP_VALUETYPE_INT16
));
552 cs_error_t
icmap_get_uint16(const char *key_name
, uint16_t *u16
)
555 return (icmap_get_int(key_name
, u16
, ICMAP_VALUETYPE_UINT16
));
558 cs_error_t
icmap_get_int32(const char *key_name
, int32_t *i32
)
561 return (icmap_get_int(key_name
, i32
, ICMAP_VALUETYPE_INT32
));
564 cs_error_t
icmap_get_uint32(const char *key_name
, uint32_t *u32
)
567 return (icmap_get_int(key_name
, u32
, ICMAP_VALUETYPE_UINT32
));
570 cs_error_t
icmap_get_int64(const char *key_name
, int64_t *i64
)
573 return(icmap_get_int(key_name
, i64
, ICMAP_VALUETYPE_INT64
));
576 cs_error_t
icmap_get_uint64(const char *key_name
, uint64_t *u64
)
579 return (icmap_get_int(key_name
, u64
, ICMAP_VALUETYPE_UINT64
));
582 cs_error_t
icmap_get_float(const char *key_name
, float *flt
)
585 return (icmap_get_int(key_name
, flt
, ICMAP_VALUETYPE_FLOAT
));
588 cs_error_t
icmap_get_double(const char *key_name
, double *dbl
)
591 return (icmap_get_int(key_name
, dbl
, ICMAP_VALUETYPE_DOUBLE
));
594 cs_error_t
icmap_get_string(const char *key_name
, char **str
)
598 icmap_value_types_t type
;
600 res
= icmap_get(key_name
, NULL
, &str_len
, &type
);
601 if (res
!= CS_OK
|| type
!= ICMAP_VALUETYPE_STRING
) {
603 res
= CS_ERR_INVALID_PARAM
;
609 *str
= malloc(str_len
);
611 res
= CS_ERR_NO_MEMORY
;
616 res
= icmap_get(key_name
, *str
, &str_len
, &type
);
628 cs_error_t
icmap_adjust_int(
629 const char *key_name
,
632 struct icmap_item
*item
;
637 cs_error_t err
= CS_OK
;
639 if (key_name
== NULL
) {
640 return (CS_ERR_INVALID_PARAM
);
643 item
= qb_map_get(icmap_map
, key_name
);
645 return (CS_ERR_NOT_EXIST
);
648 switch (item
->type
) {
649 case ICMAP_VALUETYPE_INT8
:
650 case ICMAP_VALUETYPE_UINT8
:
651 memcpy(&u8
, item
->value
, sizeof(u8
));
653 err
= icmap_set(key_name
, &u8
, sizeof(u8
), item
->type
);
655 case ICMAP_VALUETYPE_INT16
:
656 case ICMAP_VALUETYPE_UINT16
:
657 memcpy(&u16
, item
->value
, sizeof(u16
));
659 err
= icmap_set(key_name
, &u16
, sizeof(u16
), item
->type
);
661 case ICMAP_VALUETYPE_INT32
:
662 case ICMAP_VALUETYPE_UINT32
:
663 memcpy(&u32
, item
->value
, sizeof(u32
));
665 err
= icmap_set(key_name
, &u32
, sizeof(u32
), item
->type
);
667 case ICMAP_VALUETYPE_INT64
:
668 case ICMAP_VALUETYPE_UINT64
:
669 memcpy(&u64
, item
->value
, sizeof(u64
));
671 err
= icmap_set(key_name
, &u64
, sizeof(u64
), item
->type
);
673 case ICMAP_VALUETYPE_FLOAT
:
674 case ICMAP_VALUETYPE_DOUBLE
:
675 case ICMAP_VALUETYPE_STRING
:
676 case ICMAP_VALUETYPE_BINARY
:
677 err
= CS_ERR_INVALID_PARAM
;
684 cs_error_t
icmap_inc(const char *key_name
)
686 return (icmap_adjust_int(key_name
, 1));
689 cs_error_t
icmap_dec(const char *key_name
)
691 return (icmap_adjust_int(key_name
, -1));
694 icmap_iter_t
icmap_iter_init(const char *prefix
)
696 return (qb_map_pref_iter_create(icmap_map
, prefix
));
699 const char *icmap_iter_next(icmap_iter_t iter
, size_t *value_len
, icmap_value_types_t
*type
)
701 struct icmap_item
*item
;
704 res
= qb_map_iter_next(iter
, (void **)&item
);
709 if (value_len
!= NULL
) {
710 *value_len
= item
->value_len
;
720 void icmap_iter_finalize(icmap_iter_t iter
)
722 qb_map_iter_free(iter
);
725 static void icmap_notify_fn(uint32_t event
, char *key
, void *old_value
, void *value
, void *user_data
)
727 icmap_track_t icmap_track
= (icmap_track_t
)user_data
;
728 struct icmap_item
*new_item
= (struct icmap_item
*)value
;
729 struct icmap_item
*old_item
= (struct icmap_item
*)old_value
;
730 struct icmap_notify_value new_val
;
731 struct icmap_notify_value old_val
;
733 if (value
== NULL
&& old_value
== NULL
) {
737 if (new_item
!= NULL
) {
738 new_val
.type
= new_item
->type
;
739 new_val
.len
= new_item
->value_len
;
740 new_val
.data
= new_item
->value
;
742 memset(&new_val
, 0, sizeof(new_val
));
745 if (old_item
!= NULL
) {
746 old_val
.type
= old_item
->type
;
747 old_val
.len
= old_item
->value_len
;
748 old_val
.data
= old_item
->value
;
750 memset(&old_val
, 0, sizeof(old_val
));
753 icmap_track
->notify_fn(icmap_qbtt_to_tt(event
),
757 icmap_track
->user_data
);
760 cs_error_t
icmap_track_add(
761 const char *key_name
,
763 icmap_notify_fn_t notify_fn
,
765 icmap_track_t
*icmap_track
)
769 if (notify_fn
== NULL
|| icmap_track
== NULL
) {
770 return (CS_ERR_INVALID_PARAM
);
773 if ((track_type
& ~(ICMAP_TRACK_ADD
| ICMAP_TRACK_DELETE
| ICMAP_TRACK_MODIFY
| ICMAP_TRACK_PREFIX
)) != 0) {
774 return (CS_ERR_INVALID_PARAM
);
777 *icmap_track
= malloc(sizeof(**icmap_track
));
778 if (*icmap_track
== NULL
) {
779 return (CS_ERR_NO_MEMORY
);
781 memset(*icmap_track
, 0, sizeof(**icmap_track
));
783 if (key_name
!= NULL
) {
784 (*icmap_track
)->key_name
= strdup(key_name
);
787 (*icmap_track
)->track_type
= track_type
;
788 (*icmap_track
)->notify_fn
= notify_fn
;
789 (*icmap_track
)->user_data
= user_data
;
791 if ((err
= qb_map_notify_add(icmap_map
, (*icmap_track
)->key_name
, icmap_notify_fn
,
792 icmap_tt_to_qbtt(track_type
), *icmap_track
)) != 0) {
793 free((*icmap_track
)->key_name
);
796 return (qb_to_cs_error(err
));
802 cs_error_t
icmap_track_delete(icmap_track_t icmap_track
)
806 if ((err
= qb_map_notify_del_2(icmap_map
, icmap_track
->key_name
,
807 icmap_notify_fn
, icmap_tt_to_qbtt(icmap_track
->track_type
), icmap_track
)) != 0) {
808 return (qb_to_cs_error(err
));
811 free(icmap_track
->key_name
);
817 void *icmap_track_get_user_data(icmap_track_t icmap_track
)
819 return (icmap_track
->user_data
);
822 cs_error_t
icmap_set_ro_access(const char *key_name
, int prefix
, int ro_access
)
824 struct list_head
*iter
;
825 struct icmap_ro_access_item
*icmap_ro_ai
;
827 for (iter
= icmap_ro_access_item_list_head
.next
; iter
!= &icmap_ro_access_item_list_head
; iter
= iter
->next
) {
828 icmap_ro_ai
= list_entry(iter
, struct icmap_ro_access_item
, list
);
830 if (icmap_ro_ai
->prefix
== prefix
&& strcmp(key_name
, icmap_ro_ai
->key_name
) == 0) {
835 return (CS_ERR_EXIST
);
837 list_del(&icmap_ro_ai
->list
);
846 return (CS_ERR_NOT_EXIST
);
849 icmap_ro_ai
= malloc(sizeof(*icmap_ro_ai
));
850 if (icmap_ro_ai
== NULL
) {
851 return (CS_ERR_NO_MEMORY
);
854 memset(icmap_ro_ai
, 0, sizeof(*icmap_ro_ai
));
855 icmap_ro_ai
->key_name
= strdup(key_name
);
856 if (icmap_ro_ai
->key_name
== NULL
) {
858 return (CS_ERR_NO_MEMORY
);
861 icmap_ro_ai
->prefix
= prefix
;
862 list_init(&icmap_ro_ai
->list
);
863 list_add (&icmap_ro_ai
->list
, &icmap_ro_access_item_list_head
);
868 int icmap_is_key_ro(const char *key_name
)
870 struct list_head
*iter
;
871 struct icmap_ro_access_item
*icmap_ro_ai
;
873 for (iter
= icmap_ro_access_item_list_head
.next
; iter
!= &icmap_ro_access_item_list_head
; iter
= iter
->next
) {
874 icmap_ro_ai
= list_entry(iter
, struct icmap_ro_access_item
, list
);
876 if (icmap_ro_ai
->prefix
) {
877 if (strlen(icmap_ro_ai
->key_name
) > strlen(key_name
))
880 if (strncmp(icmap_ro_ai
->key_name
, key_name
, strlen(icmap_ro_ai
->key_name
)) == 0) {
884 if (strcmp(icmap_ro_ai
->key_name
, key_name
) == 0) {