libnl 1.1
lib/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-2006 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                 nl_errno(ENOMEM);
00052                 return NULL;
00053         }
00054 
00055         new->ce_refcnt = 1;
00056         nl_init_list_head(&new->ce_list);
00057 
00058         new->ce_ops = ops;
00059         if (ops->oo_constructor)
00060                 ops->oo_constructor(new);
00061 
00062         NL_DBG(4, "Allocated new object %p\n", new);
00063 
00064         return new;
00065 }
00066 
00067 /**
00068  * Allocate a new object of kind specified by the name
00069  * @arg kind            name of object type
00070  * @return The new object or nULL
00071  */
00072 struct nl_object *nl_object_alloc_name(const char *kind)
00073 {
00074         struct nl_cache_ops *ops;
00075 
00076         ops = nl_cache_ops_lookup(kind);
00077         if (!ops) {
00078                 nl_error(ENOENT, "Unable to lookup cache kind \"%s\"", kind);
00079                 return NULL;
00080         }
00081 
00082         return nl_object_alloc(ops->co_obj_ops);
00083 }
00084 
00085 struct nl_derived_object {
00086         NLHDR_COMMON
00087         char data;
00088 };
00089 
00090 /**
00091  * Allocate a new object and copy all data from an existing object
00092  * @arg obj             object to inherite data from
00093  * @return The new object or NULL.
00094  */
00095 struct nl_object *nl_object_clone(struct nl_object *obj)
00096 {
00097         struct nl_object *new;
00098         struct nl_object_ops *ops = obj_ops(obj);
00099         int doff = offsetof(struct nl_derived_object, data);
00100         int size;
00101 
00102         new = nl_object_alloc(ops);
00103         if (!new)
00104                 return NULL;
00105 
00106         size = ops->oo_size - doff;
00107         if (size < 0)
00108                 BUG();
00109 
00110         new->ce_ops = obj->ce_ops;
00111         new->ce_msgtype = obj->ce_msgtype;
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 
00269         /* Both objects must provide all required attributes to uniquely
00270          * identify an object */
00271         if ((a->ce_mask & req_attrs) != req_attrs ||
00272             (b->ce_mask & req_attrs) != req_attrs)
00273                 return 0;
00274 
00275         /* Can't judge unless we can compare */
00276         if (ops->oo_compare == NULL)
00277                 return 0;
00278 
00279         return !(ops->oo_compare(a, b, req_attrs, 0));
00280 }
00281 
00282 /**
00283  * Compute bitmask representing difference in attribute values
00284  * @arg a               an object
00285  * @arg b               another object of same type
00286  *
00287  * The bitmask returned is specific to an object type, each bit set represents
00288  * an attribute which mismatches in either of the two objects. Unavailability
00289  * of an attribute in one object and presence in the other is regarded a
00290  * mismatch as well.
00291  *
00292  * @return Bitmask describing differences or 0 if they are completely identical.
00293  */
00294 uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
00295 {
00296         struct nl_object_ops *ops = obj_ops(a);
00297 
00298         if (ops != obj_ops(b) || ops->oo_compare == NULL)
00299                 return UINT_MAX;
00300 
00301         return ops->oo_compare(a, b, ~0, 0);
00302 }
00303 
00304 /**
00305  * Match a filter against an object
00306  * @arg obj             object to check
00307  * @arg filter          object of same type acting as filter
00308  *
00309  * @return 1 if the object matches the filter or 0
00310  *           if no filter procedure is available or if the
00311  *           filter does not match.
00312  */
00313 int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
00314 {
00315         struct nl_object_ops *ops = obj_ops(obj);
00316 
00317         if (ops != obj_ops(filter) || ops->oo_compare == NULL)
00318                 return 0;
00319         
00320         return !(ops->oo_compare(obj, filter, filter->ce_mask,
00321                                  LOOSE_FLAG_COMPARISON));
00322 }
00323 
00324 /**
00325  * Convert bitmask of attributes to a character string
00326  * @arg obj             object of same type as attribute bitmask
00327  * @arg attrs           bitmask of attribute types
00328  * @arg buf             destination buffer
00329  * @arg len             length of destination buffer
00330  *
00331  * Converts the bitmask of attribute types into a list of attribute
00332  * names separated by comas.
00333  *
00334  * @return destination buffer.
00335  */
00336 char *nl_object_attrs2str(struct nl_object *obj, uint32_t attrs,
00337                           char *buf, size_t len)
00338 {
00339         struct nl_object_ops *ops = obj_ops(obj);
00340 
00341         if (ops->oo_attrs2str != NULL)
00342                 return ops->oo_attrs2str(attrs, buf, len);
00343         else {
00344                 memset(buf, 0, len);
00345                 return buf;
00346         }
00347 }
00348 
00349 /**
00350  * Return list of attributes present in an object
00351  * @arg obj             an object
00352  * @arg buf             destination buffer
00353  * @arg len             length of destination buffer
00354  *
00355  * @return destination buffer.
00356  */
00357 char *nl_object_attr_list(struct nl_object *obj, char *buf, size_t len)
00358 {
00359         return nl_object_attrs2str(obj, obj->ce_mask, buf, len);
00360 }
00361 
00362 /** @} */
00363 
00364 /**
00365  * @name Attributes
00366  * @{
00367  */
00368 
00369 int nl_object_get_refcnt(struct nl_object *obj)
00370 {
00371         return obj->ce_refcnt;
00372 }
00373 
00374 struct nl_cache *nl_object_get_cache(struct nl_object *obj)
00375 {
00376         return obj->ce_cache;
00377 }
00378 
00379 void *nl_object_priv(struct nl_object *obj)
00380 {
00381         return obj;
00382 }
00383 
00384 /** @} */
00385 
00386 /** @} */