ubusd_obj.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #include "ubusd.h"
  14. #include "ubusd_obj.h"
  15. struct avl_tree obj_types;
  16. struct avl_tree objects;
  17. struct avl_tree path;
  18. static void ubus_unref_object_type(struct ubus_object_type *type)
  19. {
  20. struct ubus_method *m;
  21. if (--type->refcount > 0)
  22. return;
  23. while (!list_empty(&type->methods)) {
  24. m = list_first_entry(&type->methods, struct ubus_method, list);
  25. list_del(&m->list);
  26. free(m);
  27. }
  28. ubus_free_id(&obj_types, &type->id);
  29. free(type);
  30. }
  31. static bool ubus_create_obj_method(struct ubus_object_type *type, struct blob_attr *attr)
  32. {
  33. struct ubus_method *m;
  34. int bloblen = blob_raw_len(attr);
  35. m = calloc(1, sizeof(*m) + bloblen);
  36. if (!m)
  37. return false;
  38. list_add_tail(&m->list, &type->methods);
  39. memcpy(m->data, attr, bloblen);
  40. m->name = blobmsg_name(m->data);
  41. return true;
  42. }
  43. static struct ubus_object_type *ubus_create_obj_type(struct blob_attr *sig)
  44. {
  45. struct ubus_object_type *type;
  46. struct blob_attr *pos;
  47. int rem;
  48. type = calloc(1, sizeof(*type));
  49. if (!type)
  50. return NULL;
  51. type->refcount = 1;
  52. if (!ubus_alloc_id(&obj_types, &type->id, 0))
  53. goto error_free;
  54. INIT_LIST_HEAD(&type->methods);
  55. blob_for_each_attr(pos, sig, rem) {
  56. if (!blobmsg_check_attr(pos, true))
  57. goto error_unref;
  58. if (!ubus_create_obj_method(type, pos))
  59. goto error_unref;
  60. }
  61. return type;
  62. error_unref:
  63. ubus_unref_object_type(type);
  64. return NULL;
  65. error_free:
  66. free(type);
  67. return NULL;
  68. }
  69. static struct ubus_object_type *ubus_get_obj_type(uint32_t obj_id)
  70. {
  71. struct ubus_object_type *type;
  72. struct ubus_id *id;
  73. id = ubus_find_id(&obj_types, obj_id);
  74. if (!id)
  75. return NULL;
  76. type = container_of(id, struct ubus_object_type, id);
  77. type->refcount++;
  78. return type;
  79. }
  80. struct ubus_object *ubusd_create_object_internal(struct ubus_object_type *type, uint32_t id)
  81. {
  82. struct ubus_object *obj;
  83. obj = calloc(1, sizeof(*obj));
  84. if (!obj)
  85. return NULL;
  86. if (!ubus_alloc_id(&objects, &obj->id, id))
  87. goto error_free;
  88. obj->type = type;
  89. INIT_LIST_HEAD(&obj->list);
  90. INIT_LIST_HEAD(&obj->events);
  91. INIT_LIST_HEAD(&obj->subscribers);
  92. INIT_LIST_HEAD(&obj->target_list);
  93. if (type)
  94. type->refcount++;
  95. return obj;
  96. error_free:
  97. free(obj);
  98. return NULL;
  99. }
  100. struct ubus_object *ubusd_create_object(struct ubus_client *cl, struct blob_attr **attr)
  101. {
  102. struct ubus_object *obj;
  103. struct ubus_object_type *type = NULL;
  104. if (attr[UBUS_ATTR_OBJTYPE])
  105. type = ubus_get_obj_type(blob_get_u32(attr[UBUS_ATTR_OBJTYPE]));
  106. else if (attr[UBUS_ATTR_SIGNATURE])
  107. type = ubus_create_obj_type(attr[UBUS_ATTR_SIGNATURE]);
  108. obj = ubusd_create_object_internal(type, 0);
  109. if (type)
  110. ubus_unref_object_type(type);
  111. if (!obj)
  112. return NULL;
  113. if (attr[UBUS_ATTR_OBJPATH]) {
  114. if (ubusd_acl_check(cl, blob_data(attr[UBUS_ATTR_OBJPATH]), NULL, UBUS_ACL_PUBLISH))
  115. goto free;
  116. obj->path.key = strdup(blob_data(attr[UBUS_ATTR_OBJPATH]));
  117. if (!obj->path.key)
  118. goto free;
  119. if (avl_insert(&path, &obj->path) != 0) {
  120. free((void *) obj->path.key);
  121. obj->path.key = NULL;
  122. goto free;
  123. }
  124. ubusd_send_obj_event(obj, true);
  125. }
  126. obj->client = cl;
  127. list_add(&obj->list, &cl->objects);
  128. return obj;
  129. free:
  130. ubusd_free_object(obj);
  131. return NULL;
  132. }
  133. void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target)
  134. {
  135. struct ubus_subscription *s;
  136. bool first = list_empty(&target->subscribers);
  137. s = calloc(1, sizeof(*s));
  138. if (!s)
  139. return;
  140. s->subscriber = obj;
  141. s->target = target;
  142. list_add(&s->list, &target->subscribers);
  143. list_add(&s->target_list, &obj->target_list);
  144. if (first)
  145. ubus_notify_subscription(target);
  146. }
  147. void ubus_unsubscribe(struct ubus_subscription *s)
  148. {
  149. struct ubus_object *obj = s->target;
  150. list_del(&s->list);
  151. list_del(&s->target_list);
  152. free(s);
  153. if (list_empty(&obj->subscribers))
  154. ubus_notify_subscription(obj);
  155. }
  156. void ubusd_free_object(struct ubus_object *obj)
  157. {
  158. struct ubus_subscription *s, *tmp;
  159. list_for_each_entry_safe(s, tmp, &obj->target_list, target_list) {
  160. ubus_unsubscribe(s);
  161. }
  162. list_for_each_entry_safe(s, tmp, &obj->subscribers, list) {
  163. ubus_notify_unsubscribe(s);
  164. }
  165. ubusd_event_cleanup_object(obj);
  166. if (obj->path.key) {
  167. ubusd_send_obj_event(obj, false);
  168. avl_delete(&path, &obj->path);
  169. free((void *) obj->path.key);
  170. }
  171. if (!list_empty(&obj->list))
  172. list_del(&obj->list);
  173. ubus_free_id(&objects, &obj->id);
  174. if (obj->type)
  175. ubus_unref_object_type(obj->type);
  176. free(obj);
  177. }
  178. static void __constructor ubusd_obj_init(void)
  179. {
  180. ubus_init_id_tree(&objects);
  181. ubus_init_id_tree(&obj_types);
  182. ubus_init_string_tree(&path, false);
  183. ubusd_event_init();
  184. ubusd_acl_init();
  185. ubusd_monitor_init();
  186. }