object.c

00001 /*
00002  * lib/object.c         Generic Cacheable Object
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup cache
00014  * @defgroup object Object
00015  * @{
00016  */
00017 
00018 #include <netlink-local.h>
00019 #include <netlink/netlink.h>
00020 #include <netlink/cache.h>
00021 #include <netlink/object.h>
00022 #include <netlink/utils.h>
00023 
00024 static inline struct nl_object_ops *obj_ops(struct nl_object *obj)
00025 {
00026         if (!obj->ce_ops)
00027                 BUG();
00028 
00029         return obj->ce_ops;
00030 }
00031 
00032 /**
00033  * @name Object Creation/Deletion
00034  * @{
00035  */
00036 
00037 /**
00038  * Allocate a new object of kind specified by the operations handle
00039  * @arg ops             cache operations handle
00040  * @return The new object or NULL
00041  */
00042 struct nl_object *nl_object_alloc(struct nl_object_ops *ops)
00043 {
00044         struct nl_object *new;
00045 
00046         if (ops->oo_size < sizeof(*new))
00047                 BUG();
00048 
00049         new = calloc(1, ops->oo_size);
00050         if (!new)
00051                 return NULL;
00052 
00053         new->ce_refcnt = 1;
00054         nl_init_list_head(&new->ce_list);
00055 
00056         new->ce_ops = ops;
00057         if (ops->oo_constructor)
00058                 ops->oo_constructor(new);
00059 
00060         NL_DBG(4, "Allocated new object %p\n", new);
00061 
00062         return new;
00063 }
00064 
00065 /**
00066  * Allocate a new object of kind specified by the name
00067  * @arg kind            name of object type
00068  * @return The new object or nULL
00069  */
00070 int nl_object_alloc_name(const char *kind, struct nl_object **result)
00071 {
00072         struct nl_cache_ops *ops;
00073 
00074         ops = nl_cache_ops_lookup(kind);
00075         if (!ops)
00076                 return -NLE_OPNOTSUPP;
00077 
00078         if (!(*result = nl_object_alloc(ops->co_obj_ops)))
00079                 return -NLE_NOMEM;
00080 
00081         return 0;
00082 }
00083 
00084 struct nl_derived_object {
00085         NLHDR_COMMON
00086         char data;
00087 };
00088 
00089 /**
00090  * Allocate a new object and copy all data from an existing object
00091  * @arg obj             object to inherite data from
00092  * @return The new object or NULL.
00093  */
00094 struct nl_object *nl_object_clone(struct nl_object *obj)
00095 {
00096         struct nl_object *new;
00097         struct nl_object_ops *ops = obj_ops(obj);
00098         int doff = offsetof(struct nl_derived_object, data);
00099         int size;
00100 
00101         new = nl_object_alloc(ops);
00102         if (!new)
00103                 return NULL;
00104 
00105         size = ops->oo_size - doff;
00106         if (size < 0)
00107                 BUG();
00108 
00109         new->ce_ops = obj->ce_ops;
00110         new->ce_msgtype = obj->ce_msgtype;
00111         new->ce_mask = obj->ce_mask;
00112 
00113         if (size)
00114                 memcpy((void *)new + doff, (void *)obj + doff, size);
00115 
00116         if (ops->oo_clone) {
00117                 if (ops->oo_clone(new, obj) < 0) {
00118                         nl_object_free(new);
00119                         return NULL;
00120                 }
00121         } else if (size && ops->oo_free_data)
00122                 BUG();
00123 
00124         return new;
00125 }
00126 
00127 /**
00128  * Free a cacheable object
00129  * @arg obj             object to free
00130  *
00131  * @return 0 or a negative error code.
00132  */
00133 void nl_object_free(struct nl_object *obj)
00134 {
00135         struct nl_object_ops *ops = obj_ops(obj);
00136 
00137         if (obj->ce_refcnt > 0)
00138                 NL_DBG(1, "Warning: Freeing object in use...\n");
00139 
00140         if (obj->ce_cache)
00141                 nl_cache_remove(obj);
00142 
00143         if (ops->oo_free_data)
00144                 ops->oo_free_data(obj);
00145 
00146         free(obj);
00147 
00148         NL_DBG(4, "Freed object %p\n", obj);
00149 }
00150 
00151 /** @} */
00152 
00153 /**
00154  * @name Reference Management
00155  * @{
00156  */
00157 
00158 /**
00159  * Acquire a reference on a object
00160  * @arg obj             object to acquire reference from
00161  */
00162 void nl_object_get(struct nl_object *obj)
00163 {
00164         obj->ce_refcnt++;
00165         NL_DBG(4, "New reference to object %p, total %d\n",
00166                obj, obj->ce_refcnt);
00167 }
00168 
00169 /**
00170  * Release a reference from an object
00171  * @arg obj             object to release reference from
00172  */
00173 void nl_object_put(struct nl_object *obj)
00174 {
00175         if (!obj)
00176                 return;
00177 
00178         obj->ce_refcnt--;
00179         NL_DBG(4, "Returned object reference %p, %d remaining\n",
00180                obj, obj->ce_refcnt);
00181 
00182         if (obj->ce_refcnt < 0)
00183                 BUG();
00184 
00185         if (obj->ce_refcnt <= 0)
00186                 nl_object_free(obj);
00187 }
00188 
00189 /**
00190  * Check whether this object is used by multiple users
00191  * @arg obj             object to check
00192  * @return true or false
00193  */
00194 int nl_object_shared(struct nl_object *obj)
00195 {
00196         return obj->ce_refcnt > 1;
00197 }
00198 
00199 /** @} */
00200 
00201 /**
00202  * @name Marks
00203  * @{
00204  */
00205 
00206 /**
00207  * Add mark to object
00208  * @arg obj             Object to mark
00209  */
00210 void nl_object_mark(struct nl_object *obj)
00211 {
00212         obj->ce_flags |= NL_OBJ_MARK;
00213 }
00214 
00215 /**
00216  * Remove mark from object
00217  * @arg obj             Object to unmark
00218  */
00219 void nl_object_unmark(struct nl_object *obj)
00220 {
00221         obj->ce_flags &= ~NL_OBJ_MARK;
00222 }
00223 
00224 /**
00225  * Return true if object is marked
00226  * @arg obj             Object to check
00227  * @return true if object is marked, otherwise false
00228  */
00229 int nl_object_is_marked(struct nl_object *obj)
00230 {
00231         return (obj->ce_flags & NL_OBJ_MARK);
00232 }
00233 
00234 /** @} */
00235 
00236 /**
00237  * @name Utillities
00238  * @{
00239  */
00240 
00241 /**
00242  * Dump this object according to the specified parameters
00243  * @arg obj             object to dump
00244  * @arg params          dumping parameters
00245  */
00246 void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params)
00247 {
00248         dump_from_ops(obj, params);
00249 }
00250 
00251 /**
00252  * Check if the identifiers of two objects are identical 
00253  * @arg a               an object
00254  * @arg b               another object of same type
00255  *
00256  * @return true if both objects have equal identifiers, otherwise false.
00257  */
00258 int nl_object_identical(struct nl_object *a, struct nl_object *b)
00259 {
00260         struct nl_object_ops *ops = obj_ops(a);
00261         int req_attrs;
00262 
00263         /* Both objects must be of same type */
00264         if (ops != obj_ops(b))
00265                 return 0;
00266 
00267         req_attrs = ops->oo_id_attrs;
00268         if (req_attrs == ~0)
00269                 req_attrs = a->ce_mask & b->ce_mask;
00270 
00271         /* Both objects must provide all required attributes to uniquely
00272          * identify an object */
00273         if ((a->ce_mask & req_attrs) != req_attrs ||
00274             (b->ce_mask & req_attrs) != req_attrs)
00275                 return 0;
00276 
00277         /* Can't judge unless we can compare */
00278         if (ops->oo_compare == NULL)
00279                 return 0;
00280 
00281         return !(ops->oo_compare(a, b, req_attrs, 0));
00282 }
00283 
00284 /**
00285  * Compute bitmask representing difference in attribute values
00286  * @arg a               an object
00287  * @arg b               another object of same type
00288  *
00289  * The bitmask returned is specific to an object type, each bit set represents
00290  * an attribute which mismatches in either of the two objects. Unavailability
00291  * of an attribute in one object and presence in the other is regarded a
00292  * mismatch as well.
00293  *
00294  * @return Bitmask describing differences or 0 if they are completely identical.
00295  */
00296 uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
00297 {
00298         struct nl_object_ops *ops = obj_ops(a);
00299 
00300         if (ops != obj_ops(b) || ops->oo_compare == NULL)
00301                 return UINT_MAX;
00302 
00303         return ops->oo_compare(a, b, ~0, 0);
00304 }
00305 
00306 /**
00307  * Match a filter against an object
00308  * @arg obj             object to check
00309  * @arg filter          object of same type acting as filter
00310  *
00311  * @return 1 if the object matches the filter or 0
00312  *           if no filter procedure is available or if the
00313  *           filter does not match.
00314  */
00315 int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
00316 {
00317         struct nl_object_ops *ops = obj_ops(obj);
00318 
00319         if (ops != obj_ops(filter) || ops->oo_compare == NULL)
00320                 return 0;
00321         
00322         return !(ops->oo_compare(obj, filter, filter->ce_mask,
00323                                  LOOSE_COMPARISON));
00324 }
00325 
00326 /**
00327  * Convert bitmask of attributes to a character string
00328  * @arg obj             object of same type as attribute bitmask
00329  * @arg attrs           bitmask of attribute types
00330  * @arg buf             destination buffer
00331  * @arg len             length of destination buffer
00332  *
00333  * Converts the bitmask of attribute types into a list of attribute
00334  * names separated by comas.
00335  *
00336  * @return destination buffer.
00337  */
00338 char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs,
00339                           char *buf, size_t len)
00340 {
00341         struct nl_object_ops *ops = obj_ops(obj);
00342 
00343         if (ops->oo_attrs2str != NULL)
00344                 return ops->oo_attrs2str(attrs, buf, len);
00345         else {
00346                 memset(buf, 0, len);
00347                 return buf;
00348         }
00349 }
00350 
00351 /**
00352  * Return list of attributes present in an object
00353  * @arg obj             an object
00354  * @arg buf             destination buffer
00355  * @arg len             length of destination buffer
00356  *
00357  * @return destination buffer.
00358  */
00359 char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
00360 {
00361         return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
00362 }
00363 
00364 /** @} */
00365 
00366 /**
00367  * @name Attributes
00368  * @{
00369  */
00370 
00371 int nl_object_get_refcnt(struct nl_object *obj)
00372 {
00373         return obj->ce_refcnt;
00374 }
00375 
00376 struct nl_cache *nl_object_get_cache(struct nl_object *obj)
00377 {
00378         return obj->ce_cache;
00379 }
00380 
00381 /** @} */
00382 
00383 /** @} */