2 * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org>
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
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.
15 #include "ubusd_obj.h"
17 struct avl_tree obj_types
;
18 struct avl_tree objects
;
21 static void ubus_unref_object_type(struct ubus_object_type
*type
)
23 struct ubus_method
*m
, *tmp
;
25 if (--type
->refcount
> 0)
28 list_for_each_entry_safe(m
, tmp
, &type
->methods
, list
) {
33 ubus_free_id(&obj_types
, &type
->id
);
37 static bool ubus_create_obj_method(struct ubus_object_type
*type
, struct blob_attr
*attr
)
39 struct ubus_method
*m
;
40 int bloblen
= blob_raw_len(attr
);
42 m
= calloc(1, sizeof(*m
) + bloblen
);
46 list_add_tail(&m
->list
, &type
->methods
);
47 memcpy(m
->data
, attr
, bloblen
);
48 m
->name
= blobmsg_name(m
->data
);
53 static struct ubus_object_type
*ubus_create_obj_type(struct blob_attr
*sig
)
55 struct ubus_object_type
*type
;
56 struct blob_attr
*pos
;
59 type
= calloc(1, sizeof(*type
));
65 if (!ubus_alloc_id(&obj_types
, &type
->id
, 0))
68 INIT_LIST_HEAD(&type
->methods
);
70 blob_for_each_attr(pos
, sig
, rem
) {
71 if (!blobmsg_check_attr(pos
, true))
74 if (!ubus_create_obj_method(type
, pos
))
81 ubus_unref_object_type(type
);
89 static struct ubus_object_type
*ubus_get_obj_type(uint32_t obj_id
)
91 struct ubus_object_type
*type
;
94 id
= ubus_find_id(&obj_types
, obj_id
);
98 type
= container_of(id
, struct ubus_object_type
, id
);
103 struct ubus_object
*ubusd_create_object_internal(struct ubus_object_type
*type
, uint32_t id
)
105 struct ubus_object
*obj
;
107 obj
= calloc(1, sizeof(*obj
));
111 if (!ubus_alloc_id(&objects
, &obj
->id
, id
))
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
);
129 struct ubus_object
*ubusd_create_object(struct ubus_client
*cl
, struct blob_attr
**attr
)
131 struct ubus_object
*obj
;
132 struct ubus_object_type
*type
= NULL
;
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
]);
139 obj
= ubusd_create_object_internal(type
, 0);
141 ubus_unref_object_type(type
);
146 if (attr
[UBUS_ATTR_OBJPATH
]) {
147 if (ubusd_acl_check(cl
, blob_data(attr
[UBUS_ATTR_OBJPATH
]), NULL
, UBUS_ACL_PUBLISH
))
150 obj
->path
.key
= strdup(blob_data(attr
[UBUS_ATTR_OBJPATH
]));
154 if (avl_insert(&path
, &obj
->path
) != 0) {
155 free((void *) obj
->path
.key
);
156 obj
->path
.key
= NULL
;
159 ubusd_send_obj_event(obj
, true);
163 list_add(&obj
->list
, &cl
->objects
);
168 ubusd_free_object(obj
);
172 void ubus_subscribe(struct ubus_object
*obj
, struct ubus_object
*target
)
174 struct ubus_subscription
*s
;
175 bool first
= list_empty(&target
->subscribers
);
177 s
= calloc(1, sizeof(*s
));
183 list_add(&s
->list
, &target
->subscribers
);
184 list_add(&s
->target_list
, &obj
->target_list
);
187 ubus_notify_subscription(target
);
190 void ubus_unsubscribe(struct ubus_subscription
*s
)
192 struct ubus_object
*obj
= s
->target
;
195 list_del(&s
->target_list
);
198 if (list_empty(&obj
->subscribers
))
199 ubus_notify_subscription(obj
);
202 void ubusd_free_object(struct ubus_object
*obj
)
204 struct ubus_subscription
*s
, *tmp
;
206 list_for_each_entry_safe(s
, tmp
, &obj
->target_list
, target_list
) {
209 list_for_each_entry_safe(s
, tmp
, &obj
->subscribers
, list
) {
210 ubus_notify_unsubscribe(s
);
213 ubusd_event_cleanup_object(obj
);
215 ubusd_send_obj_event(obj
, false);
216 avl_delete(&path
, &obj
->path
);
217 free((void *) obj
->path
.key
);
219 if (!list_empty(&obj
->list
))
220 list_del(&obj
->list
);
221 ubus_free_id(&objects
, &obj
->id
);
223 ubus_unref_object_type(obj
->type
);
227 static void __constructor
ubusd_obj_init(void)
229 ubus_init_id_tree(&objects
);
230 ubus_init_id_tree(&obj_types
);
231 ubus_init_string_tree(&path
, false);
234 ubusd_monitor_init();