1 /* 2 * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include "ubusd.h" 15 #include "ubusd_obj.h" 16 17 struct avl_tree obj_types; 18 struct avl_tree objects; 19 struct avl_tree path; 20 21 static void ubus_unref_object_type(struct ubus_object_type *type) 22 { 23 struct ubus_method *m, *tmp; 24 25 if (--type->refcount > 0) 26 return; 27 28 list_for_each_entry_safe(m, tmp, &type->methods, list) { 29 list_del(&m->list); 30 free(m); 31 } 32 33 ubus_free_id(&obj_types, &type->id); 34 free(type); 35 } 36 37 static bool ubus_create_obj_method(struct ubus_object_type *type, struct blob_attr *attr) 38 { 39 struct ubus_method *m; 40 int bloblen = blob_raw_len(attr); 41 42 m = calloc(1, sizeof(*m) + bloblen); 43 if (!m) 44 return false; 45 46 list_add_tail(&m->list, &type->methods); 47 memcpy(m->data, attr, bloblen); 48 m->name = blobmsg_name(m->data); 49 50 return true; 51 } 52 53 static struct ubus_object_type *ubus_create_obj_type(struct blob_attr *sig) 54 { 55 struct ubus_object_type *type; 56 struct blob_attr *pos; 57 size_t rem; 58 59 type = calloc(1, sizeof(*type)); 60 if (!type) 61 return NULL; 62 63 type->refcount = 1; 64 65 if (!ubus_alloc_id(&obj_types, &type->id, 0)) 66 goto error_free; 67 68 INIT_LIST_HEAD(&type->methods); 69 70 blob_for_each_attr(pos, sig, rem) { 71 if (!blobmsg_check_attr(pos, true)) 72 goto error_unref; 73 74 if (!ubus_create_obj_method(type, pos)) 75 goto error_unref; 76 } 77 78 return type; 79 80 error_unref: 81 ubus_unref_object_type(type); 82 return NULL; 83 84 error_free: 85 free(type); 86 return NULL; 87 } 88 89 static struct ubus_object_type *ubus_get_obj_type(uint32_t obj_id) 90 { 91 struct ubus_object_type *type; 92 struct ubus_id *id; 93 94 id = ubus_find_id(&obj_types, obj_id); 95 if (!id) 96 return NULL; 97 98 type = container_of(id, struct ubus_object_type, id); 99 type->refcount++; 100 return type; 101 } 102 103 struct ubus_object *ubusd_create_object_internal(struct ubus_object_type *type, uint32_t id) 104 { 105 struct ubus_object *obj; 106 107 obj = calloc(1, sizeof(*obj)); 108 if (!obj) 109 return NULL; 110 111 if (!ubus_alloc_id(&objects, &obj->id, id)) 112 goto error_free; 113 114 obj->type = type; 115 INIT_LIST_HEAD(&obj->list); 116 INIT_LIST_HEAD(&obj->events); 117 INIT_LIST_HEAD(&obj->subscribers); 118 INIT_LIST_HEAD(&obj->target_list); 119 if (type) 120 type->refcount++; 121 122 return obj; 123 124 error_free: 125 free(obj); 126 return NULL; 127 } 128 129 struct ubus_object *ubusd_create_object(struct ubus_client *cl, struct blob_attr **attr) 130 { 131 struct ubus_object *obj; 132 struct ubus_object_type *type = NULL; 133 134 if (attr[UBUS_ATTR_OBJTYPE]) 135 type = ubus_get_obj_type(blob_get_u32(attr[UBUS_ATTR_OBJTYPE])); 136 else if (attr[UBUS_ATTR_SIGNATURE]) 137 type = ubus_create_obj_type(attr[UBUS_ATTR_SIGNATURE]); 138 139 obj = ubusd_create_object_internal(type, 0); 140 if (type) 141 ubus_unref_object_type(type); 142 143 if (!obj) 144 return NULL; 145 146 if (attr[UBUS_ATTR_OBJPATH]) { 147 if (ubusd_acl_check(cl, blob_data(attr[UBUS_ATTR_OBJPATH]), NULL, UBUS_ACL_PUBLISH)) 148 goto free; 149 150 obj->path.key = strdup(blob_data(attr[UBUS_ATTR_OBJPATH])); 151 if (!obj->path.key) 152 goto free; 153 154 if (avl_insert(&path, &obj->path) != 0) { 155 free((void *) obj->path.key); 156 obj->path.key = NULL; 157 goto free; 158 } 159 ubusd_send_obj_event(obj, true); 160 } 161 162 obj->client = cl; 163 list_add(&obj->list, &cl->objects); 164 165 return obj; 166 167 free: 168 ubusd_free_object(obj); 169 return NULL; 170 } 171 172 void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target) 173 { 174 struct ubus_subscription *s; 175 bool first = list_empty(&target->subscribers); 176 177 s = calloc(1, sizeof(*s)); 178 if (!s) 179 return; 180 181 s->subscriber = obj; 182 s->target = target; 183 list_add(&s->list, &target->subscribers); 184 list_add(&s->target_list, &obj->target_list); 185 186 if (first) 187 ubus_notify_subscription(target); 188 } 189 190 void ubus_unsubscribe(struct ubus_subscription *s) 191 { 192 struct ubus_object *obj = s->target; 193 194 list_del(&s->list); 195 list_del(&s->target_list); 196 free(s); 197 198 if (list_empty(&obj->subscribers)) 199 ubus_notify_subscription(obj); 200 } 201 202 void ubusd_free_object(struct ubus_object *obj) 203 { 204 struct ubus_subscription *s, *tmp; 205 206 list_for_each_entry_safe(s, tmp, &obj->target_list, target_list) { 207 ubus_unsubscribe(s); 208 } 209 list_for_each_entry_safe(s, tmp, &obj->subscribers, list) { 210 ubus_notify_unsubscribe(s); 211 } 212 213 ubusd_event_cleanup_object(obj); 214 if (obj->path.key) { 215 ubusd_send_obj_event(obj, false); 216 avl_delete(&path, &obj->path); 217 free((void *) obj->path.key); 218 } 219 if (!list_empty(&obj->list)) 220 list_del(&obj->list); 221 ubus_free_id(&objects, &obj->id); 222 if (obj->type) 223 ubus_unref_object_type(obj->type); 224 free(obj); 225 } 226 227 static void __constructor ubusd_obj_init(void) 228 { 229 ubus_init_id_tree(&objects); 230 ubus_init_id_tree(&obj_types); 231 ubus_init_string_tree(&path, false); 232 ubusd_event_init(); 233 ubusd_acl_init(); 234 ubusd_monitor_init(); 235 } 236
This page was automatically generated by LXR 0.3.1. • OpenWrt