astobj2: Made use OBJ_SEARCH_xxx identifiers as field enum values internally.
authorRichard Mudgett <rmudgett@digium.com>
Tue, 24 Sep 2013 22:55:06 +0000 (22:55 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 24 Sep 2013 22:55:06 +0000 (22:55 +0000)
* Made ao2_unlink to protect itself from stray OBJ_SEARCH_xxx values
passed in.
........

Merged revisions 399749 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@399750 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/astobj2.c

index cc1e257..008c803 100644 (file)
@@ -1190,7 +1190,8 @@ void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
                return NULL;
        }
 
-       flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+       flags &= ~OBJ_SEARCH_MASK;
+       flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
        __ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
 
        return NULL;
@@ -1204,7 +1205,8 @@ void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
                return NULL;
        }
 
-       flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+       flags &= ~OBJ_SEARCH_MASK;
+       flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
        __ao2_callback(c, flags, ao2_match_by_addr, user_data);
 
        return NULL;
@@ -2138,7 +2140,7 @@ static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *sel
                return NULL;
        }
 
-       i = abs(self->hash_fn(obj_new, OBJ_POINTER));
+       i = abs(self->hash_fn(obj_new, OBJ_SEARCH_OBJECT));
        i %= self->n_buckets;
 
        if (tag) {
@@ -2178,7 +2180,7 @@ static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash
        if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
                if (sort_fn) {
                        AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&bucket->list, cur, links) {
-                               cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
+                               cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                                if (cmp > 0) {
                                        continue;
                                }
@@ -2210,7 +2212,7 @@ static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash
        } else {
                if (sort_fn) {
                        AST_DLLIST_TRAVERSE_SAFE_BEGIN(&bucket->list, cur, links) {
-                               cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
+                               cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                                if (cmp < 0) {
                                        continue;
                                }
@@ -2310,15 +2312,24 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
         * If lookup by pointer or search key, run the hash and optional
         * sort functions.  Otherwise, traverse the whole container.
         */
-       if (flags & (OBJ_POINTER | OBJ_KEY)) {
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_OBJECT:
+       case OBJ_SEARCH_KEY:
                /* we know hash can handle this case */
-               bucket_cur = abs(self->hash_fn(arg, flags & (OBJ_POINTER | OBJ_KEY)));
+               bucket_cur = abs(self->hash_fn(arg, flags & OBJ_SEARCH_MASK));
                bucket_cur %= self->n_buckets;
                state->sort_fn = self->common.sort_fn;
-       } else {
+               break;
+       case OBJ_SEARCH_PARTIAL_KEY:
+               /* scan all buckets for partial key matches */
+               bucket_cur = -1;
+               state->sort_fn = self->common.sort_fn;
+               break;
+       default:
                /* don't know, let's scan all buckets */
                bucket_cur = -1;
-               state->sort_fn = (flags & OBJ_PARTIAL_KEY) ? self->common.sort_fn : NULL;
+               state->sort_fn = NULL;
+               break;
        }
 
        if (state->descending) {
@@ -2354,8 +2365,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
 
                                if (state->sort_fn) {
                                        /* Filter node through the sort_fn */
-                                       cmp = state->sort_fn(node->common.obj, arg,
-                                               flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+                                       cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
                                        if (cmp > 0) {
                                                continue;
                                        }
@@ -2380,7 +2390,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
                        /* Was this the starting bucket? */
                        if (bucket_cur == state->bucket_start
                                && (flags & OBJ_CONTINUE)
-                               && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+                               && (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
                                /* In case the bucket was empty or none of the nodes matched. */
                                state->sort_fn = NULL;
                        }
@@ -2388,7 +2398,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
                        /* Was this the first container bucket? */
                        if (bucket_cur == 0
                                && (flags & OBJ_CONTINUE)
-                               && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+                               && (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
                                /* Move to the end to ensure we check every bucket */
                                bucket_cur = self->n_buckets;
                                state->bucket_last = state->bucket_start + 1;
@@ -2435,8 +2445,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
 
                                if (state->sort_fn) {
                                        /* Filter node through the sort_fn */
-                                       cmp = state->sort_fn(node->common.obj, arg,
-                                               flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+                                       cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
                                        if (cmp < 0) {
                                                continue;
                                        }
@@ -2461,7 +2470,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
                        /* Was this the starting bucket? */
                        if (bucket_cur == state->bucket_start
                                && (flags & OBJ_CONTINUE)
-                               && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+                               && (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
                                /* In case the bucket was empty or none of the nodes matched. */
                                state->sort_fn = NULL;
                        }
@@ -2469,7 +2478,7 @@ static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *s
                        /* Was this the last container bucket? */
                        if (bucket_cur == self->n_buckets - 1
                                && (flags & OBJ_CONTINUE)
-                               && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+                               && (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
                                /* Move to the beginning to ensure we check every bucket */
                                bucket_cur = -1;
                                state->bucket_last = state->bucket_start;
@@ -2542,8 +2551,7 @@ static struct hash_bucket_node *hash_ao2_find_next(struct ao2_container_hash *se
 
                                if (state->sort_fn) {
                                        /* Filter node through the sort_fn */
-                                       cmp = state->sort_fn(node->common.obj, arg,
-                                               flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+                                       cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
                                        if (cmp > 0) {
                                                continue;
                                        }
@@ -2574,7 +2582,7 @@ hash_descending_resume:;
                        /* Was this the first container bucket? */
                        if (bucket_cur == 0
                                && (flags & OBJ_CONTINUE)
-                               && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+                               && (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
                                /* Move to the end to ensure we check every bucket */
                                bucket_cur = self->n_buckets;
                                state->bucket_last = state->bucket_start + 1;
@@ -2609,8 +2617,7 @@ hash_descending_resume:;
 
                                if (state->sort_fn) {
                                        /* Filter node through the sort_fn */
-                                       cmp = state->sort_fn(node->common.obj, arg,
-                                               flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+                                       cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
                                        if (cmp < 0) {
                                                continue;
                                        }
@@ -2641,7 +2648,7 @@ hash_ascending_resume:;
                        /* Was this the last container bucket? */
                        if (bucket_cur == self->n_buckets - 1
                                && (flags & OBJ_CONTINUE)
-                               && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+                               && (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
                                /* Move to the beginning to ensure we check every bucket */
                                bucket_cur = -1;
                                state->bucket_last = state->bucket_start;
@@ -3043,7 +3050,7 @@ static int hash_ao2_integrity(struct ao2_container_hash *self)
                        ++count_obj;
 
                        /* Check container hash key for expected bucket. */
-                       bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_POINTER));
+                       bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_SEARCH_OBJECT));
                        bucket_exp %= self->n_buckets;
                        if (bucket != bucket_exp) {
                                ast_log(LOG_ERROR, "Bucket %d node hashes to bucket %d!\n",
@@ -3054,7 +3061,7 @@ static int hash_ao2_integrity(struct ao2_container_hash *self)
                        /* Check sort if configured. */
                        if (self->common.sort_fn) {
                                if (obj_last
-                                       && self->common.sort_fn(obj_last, node->common.obj, OBJ_POINTER) > 0) {
+                                       && self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
                                        ast_log(LOG_ERROR, "Bucket %d nodes out of sorted order!\n",
                                                bucket);
                                        return -1;
@@ -3510,9 +3517,9 @@ enum empty_node_direction {
  * \param sort_fn Sort comparison function for non-empty nodes.
  * \param obj_right pointer to the (user-defined part) of an object.
  * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
+ *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
+ *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
  * \param bias How to bias search direction for duplicates
  *
  * \return enum empty_node_direction to proceed.
@@ -4260,7 +4267,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree
        for (;;) {
                if (!cur->common.obj) {
                        /* Which direction do we go to insert this node? */
-                       if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_POINTER, bias)
+                       if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_SEARCH_OBJECT, bias)
                                == GO_LEFT) {
                                if (cur->left) {
                                        cur = cur->left;
@@ -4284,7 +4291,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree
                        rb_insert_fixup(self, node);
                        return AO2_CONTAINER_INSERT_NODE_INSERTED;
                }
-               cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
+               cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                if (cmp > 0) {
                        if (cur->left) {
                                cur = cur->left;
@@ -4366,7 +4373,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree
                                        /* Reject inserting the same object */
                                        return AO2_CONTAINER_INSERT_NODE_REJECTED;
                                }
-                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                                if (cmp) {
                                        break;
                                }
@@ -4382,7 +4389,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree
                                        /* Reject inserting the same object */
                                        return AO2_CONTAINER_INSERT_NODE_REJECTED;
                                }
-                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                                if (cmp) {
                                        break;
                                }
@@ -4407,7 +4414,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree
                                        /* Reject inserting the same object */
                                        return AO2_CONTAINER_INSERT_NODE_REJECTED;
                                }
-                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                                if (cmp) {
                                        break;
                                }
@@ -4423,7 +4430,7 @@ static enum ao2_container_insert rb_ao2_insert_node(struct ao2_container_rbtree
                                        /* Reject inserting the same object */
                                        return AO2_CONTAINER_INSERT_NODE_REJECTED;
                                }
-                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+                               cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
                                if (cmp) {
                                        break;
                                }
@@ -4544,8 +4551,7 @@ static struct rbtree_node *rb_ao2_find_next(struct ao2_container_rbtree *self, s
 
                if (state->sort_fn) {
                        /* Filter node through the sort_fn */
-                       cmp = state->sort_fn(node->common.obj, arg,
-                               flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+                       cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
                        if (cmp) {
                                /* No more nodes in this container are possible to match. */
                                break;
@@ -4581,9 +4587,9 @@ static struct rbtree_node *rb_ao2_find_next(struct ao2_container_rbtree *self, s
  * \param self Container to operate upon.
  * \param obj_right pointer to the (user-defined part) of an object.
  * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
+ *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
+ *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
  *   OBJ_CONTINUE - if set, return node right before or right after search key if not a match.
  * \param bias How to bias search direction for duplicates
  *
@@ -4598,7 +4604,7 @@ static struct rbtree_node *rb_find_initial(struct ao2_container_rbtree *self, vo
        struct rbtree_node *next = NULL;
        ao2_sort_fn *sort_fn;
 
-       sort_flags = flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY);
+       sort_flags = flags & OBJ_SEARCH_MASK;
        sort_fn = self->common.sort_fn;
 
        /* Find node where normal search would find it. */
@@ -4731,12 +4737,17 @@ static struct rbtree_node *rb_ao2_find_first(struct ao2_container_rbtree *self,
        state->arg = arg;
        state->flags = flags;
 
-       if (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_OBJECT:
+       case OBJ_SEARCH_KEY:
+       case OBJ_SEARCH_PARTIAL_KEY:
                /* We are asked to do a directed search. */
                state->sort_fn = self->common.sort_fn;
-       } else {
+               break;
+       default:
                /* Don't know, let's visit all nodes */
                state->sort_fn = NULL;
+               break;
        }
 
        if (!self->root) {
@@ -4764,7 +4775,7 @@ static struct rbtree_node *rb_ao2_find_first(struct ao2_container_rbtree *self,
                switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
                case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
                case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-                       if ((flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) != OBJ_PARTIAL_KEY) {
+                       if ((flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_PARTIAL_KEY) {
                                /* There are no duplicates allowed. */
                                bias = BIAS_EQUAL;
                                break;
@@ -4799,7 +4810,7 @@ static struct rbtree_node *rb_ao2_find_first(struct ao2_container_rbtree *self,
                switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
                case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
                case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-                       if ((flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) != OBJ_PARTIAL_KEY) {
+                       if ((flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_PARTIAL_KEY) {
                                /* There are no duplicates allowed. */
                                bias = BIAS_EQUAL;
                                break;
@@ -5229,7 +5240,7 @@ static int rb_ao2_integrity(struct ao2_container_rbtree *self)
                        }
 
                        if (obj_last) {
-                               if (self->common.sort_fn(obj_last, node->common.obj, OBJ_POINTER) > 0) {
+                               if (self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
                                        ast_log(LOG_ERROR, "Tree nodes are out of sorted order!\n");
                                        return -1;
                                }
@@ -5518,18 +5529,33 @@ static int ao2_reg_sort_cb(const void *obj_left, const void *obj_right, int flag
        const struct ao2_reg_container *reg_left = obj_left;
        int cmp;
 
-       if (flags & OBJ_KEY) {
-               const char *name = obj_right;
+       switch (flags & OBJ_SEARCH_MASK) {
+       case OBJ_SEARCH_OBJECT:
+               {
+                       const struct ao2_reg_container *reg_right = obj_right;
 
-               cmp = strcasecmp(reg_left->name, name);
-       } else if (flags & OBJ_PARTIAL_KEY) {
-               const struct ao2_reg_partial_key *partial_key = obj_right;
+                       cmp = strcasecmp(reg_left->name, reg_right->name);
+               }
+               break;
+       case OBJ_SEARCH_KEY:
+               {
+                       const char *name = obj_right;
 
-               cmp = strncasecmp(reg_left->name, partial_key->name, partial_key->len);
-       } else {
-               const struct ao2_reg_container *reg_right = obj_right;
+                       cmp = strcasecmp(reg_left->name, name);
+               }
+               break;
+       case OBJ_SEARCH_PARTIAL_KEY:
+               {
+                       const struct ao2_reg_partial_key *partial_key = obj_right;
 
-               cmp = strcasecmp(reg_left->name, reg_right->name);
+                       cmp = strncasecmp(reg_left->name, partial_key->name, partial_key->len);
+               }
+               break;
+       default:
+               /* Sort can only work on something with a full or partial key. */
+               ast_assert(0);
+               cmp = 0;
+               break;
        }
        return cmp;
 }
@@ -5576,7 +5602,7 @@ int ao2_container_register(const char *name, struct ao2_container *self, ao2_prn
 void ao2_container_unregister(const char *name)
 {
 #if defined(AST_DEVMODE)
-       ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_KEY,
+       ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_SEARCH_KEY,
                "Unregister container");
 #endif /* defined(AST_DEVMODE) */
 }
@@ -5607,7 +5633,7 @@ static char *complete_container_names(struct ast_cli_args *a)
        partial_key.name = a->word;
        which.find_nth = a->n;
        which.count = 0;
-       reg = ao2_t_callback_data(reg_containers, partial_key.len ? OBJ_PARTIAL_KEY : 0,
+       reg = ao2_t_callback_data(reg_containers, partial_key.len ? OBJ_SEARCH_PARTIAL_KEY : 0,
                ao2_complete_reg_cb, &partial_key, &which, "Find partial registered container");
        if (reg) {
                name = ast_strdup(reg->name);
@@ -5676,7 +5702,7 @@ static char *handle_cli_astobj2_container_dump(struct ast_cli_entry *e, int cmd,
        }
 
        name = a->argv[3];
-       reg = ao2_t_find(reg_containers, name, OBJ_KEY, "Find registered container");
+       reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
        if (reg) {
                ao2_container_dump(reg->registered, 0, name, (void *) &a->fd, cli_output,
                        reg->prnt_obj);
@@ -5712,7 +5738,7 @@ static char *handle_cli_astobj2_container_stats(struct ast_cli_entry *e, int cmd
        }
 
        name = a->argv[3];
-       reg = ao2_t_find(reg_containers, name, OBJ_KEY, "Find registered container");
+       reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
        if (reg) {
                ao2_container_stats(reg->registered, 0, name, (void *) &a->fd, cli_output);
                ao2_t_ref(reg, -1, "Done with registered container object.");
@@ -5747,7 +5773,7 @@ static char *handle_cli_astobj2_container_check(struct ast_cli_entry *e, int cmd
        }
 
        name = a->argv[3];
-       reg = ao2_t_find(reg_containers, name, OBJ_KEY, "Find registered container");
+       reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
        if (reg) {
                ast_cli(a->fd, "Container check of '%s': %s.\n", name,
                        ao2_container_check(reg->registered, 0) ? "failed" : "OK");