| /* |
| * lib/cache_mngt.c Cache Management |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation version 2.1 |
| * of the License. |
| * |
| * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> |
| */ |
| |
| /** |
| * @defgroup cache_mngt Caching |
| * @{ |
| */ |
| |
| #include <netlink-local.h> |
| #include <netlink/netlink.h> |
| #include <netlink/cache.h> |
| #include <netlink/utils.h> |
| |
| static struct nl_cache_ops *cache_ops; |
| |
| /** |
| * @name Cache Operations Sets |
| * @{ |
| */ |
| |
| /** |
| * Lookup the set cache operations of a certain cache type |
| * @arg name name of the cache type |
| * |
| * @return The cache operations or NULL if no operations |
| * have been registered under the specified name. |
| */ |
| struct nl_cache_ops *nl_cache_ops_lookup(const char *name) |
| { |
| struct nl_cache_ops *ops; |
| |
| for (ops = cache_ops; ops; ops = ops->co_next) |
| if (!strcmp(ops->co_name, name)) |
| return ops; |
| |
| return NULL; |
| } |
| |
| /** |
| * Associate a message type to a set of cache operations |
| * @arg protocol netlink protocol |
| * @arg msgtype netlink message type |
| * |
| * Associates the specified netlink message type with |
| * a registered set of cache operations. |
| * |
| * @return The cache operations or NULL if no association |
| * could be made. |
| */ |
| struct nl_cache_ops *nl_cache_ops_associate(int protocol, int msgtype) |
| { |
| int i; |
| struct nl_cache_ops *ops; |
| |
| for (ops = cache_ops; ops; ops = ops->co_next) |
| for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) |
| if (ops->co_msgtypes[i].mt_id == msgtype && |
| ops->co_protocol == protocol) |
| return ops; |
| |
| return NULL; |
| } |
| |
| /** |
| * Lookup message type cache association |
| * @arg ops cache operations |
| * @arg msgtype netlink message type |
| * |
| * Searches for a matching message type association ing the specified |
| * cache operations. |
| * |
| * @return A message type association or NULL. |
| */ |
| struct nl_msgtype *nl_msgtype_lookup(struct nl_cache_ops *ops, int msgtype) |
| { |
| int i; |
| |
| for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++) |
| if (ops->co_msgtypes[i].mt_id == msgtype) |
| return &ops->co_msgtypes[i]; |
| |
| return NULL; |
| } |
| |
| static struct nl_cache_ops *cache_ops_lookup_for_obj(struct nl_object_ops *obj_ops) |
| { |
| struct nl_cache_ops *ops; |
| |
| for (ops = cache_ops; ops; ops = ops->co_next) |
| if (ops->co_obj_ops == obj_ops) |
| return ops; |
| |
| return NULL; |
| |
| } |
| |
| /** |
| * Call a function for each registered cache operation |
| * @arg cb Callback function to be called |
| * @arg arg User specific argument. |
| */ |
| void nl_cache_ops_foreach(void (*cb)(struct nl_cache_ops *, void *), void *arg) |
| { |
| struct nl_cache_ops *ops; |
| |
| for (ops = cache_ops; ops; ops = ops->co_next) |
| cb(ops, arg); |
| } |
| |
| /** |
| * Register a set of cache operations |
| * @arg ops cache operations |
| * |
| * Called by users of caches to announce the avaibility of |
| * a certain cache type. |
| * |
| * @return 0 on success or a negative error code. |
| */ |
| int nl_cache_mngt_register(struct nl_cache_ops *ops) |
| { |
| if (!ops->co_name) |
| return nl_error(EINVAL, "No cache name specified"); |
| |
| if (!ops->co_obj_ops) |
| return nl_error(EINVAL, "No obj cache ops specified"); |
| |
| if (nl_cache_ops_lookup(ops->co_name)) |
| return nl_error(EEXIST, "Cache operations already exist"); |
| |
| ops->co_next = cache_ops; |
| cache_ops = ops; |
| |
| NL_DBG(1, "Registered cache operations %s\n", ops->co_name); |
| |
| return 0; |
| } |
| |
| /** |
| * Unregister a set of cache operations |
| * @arg ops cache operations |
| * |
| * Called by users of caches to announce a set of |
| * cache operations is no longer available. The |
| * specified cache operations must have been registered |
| * previously using nl_cache_mngt_register() |
| * |
| * @return 0 on success or a negative error code |
| */ |
| int nl_cache_mngt_unregister(struct nl_cache_ops *ops) |
| { |
| struct nl_cache_ops *t, **tp; |
| |
| for (tp = &cache_ops; (t=*tp) != NULL; tp = &t->co_next) |
| if (t == ops) |
| break; |
| |
| if (!t) |
| return nl_error(ENOENT, "No such cache operations"); |
| |
| NL_DBG(1, "Unregistered cache operations %s\n", ops->co_name); |
| |
| *tp = t->co_next; |
| return 0; |
| } |
| |
| /** @} */ |
| |
| /** |
| * @name Global Cache Provisioning/Requiring |
| * @{ |
| */ |
| |
| /** |
| * Provide a cache for global use |
| * @arg cache cache to provide |
| * |
| * Offers the specified cache to be used by other modules. |
| * Only one cache per type may be shared at a time, |
| * a previsouly provided caches will be overwritten. |
| */ |
| void nl_cache_mngt_provide(struct nl_cache *cache) |
| { |
| struct nl_cache_ops *ops; |
| |
| ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops); |
| if (!ops) |
| BUG(); |
| else |
| ops->co_major_cache = cache; |
| } |
| |
| /** |
| * Unprovide a cache for global use |
| * @arg cache cache to unprovide |
| * |
| * Cancels the offer to use a cache globally. The |
| * cache will no longer be returned via lookups but |
| * may still be in use. |
| */ |
| void nl_cache_mngt_unprovide(struct nl_cache *cache) |
| { |
| struct nl_cache_ops *ops; |
| |
| ops = cache_ops_lookup_for_obj(cache->c_ops->co_obj_ops); |
| if (!ops) |
| BUG(); |
| else if (ops->co_major_cache == cache) |
| ops->co_major_cache = NULL; |
| } |
| |
| /** |
| * Demand the use of a global cache |
| * @arg name name of the required object type |
| * |
| * Trys to find a cache of the specified type for global |
| * use. |
| * |
| * @return A cache provided by another subsystem of the |
| * specified type marked to be available. |
| */ |
| struct nl_cache *nl_cache_mngt_require(const char *name) |
| { |
| struct nl_cache_ops *ops; |
| |
| ops = nl_cache_ops_lookup(name); |
| if (!ops || !ops->co_major_cache) { |
| fprintf(stderr, "Application BUG: Your application must " |
| "call nl_cache_mngt_provide() and\nprovide a valid " |
| "%s cache to be used for internal lookups.\nSee the " |
| " API documentation for more details.\n", name); |
| |
| return NULL; |
| } |
| |
| return ops->co_major_cache; |
| } |
| |
| /** @} */ |
| |
| /** @} */ |