ubusd_event.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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 <arpa/inet.h>
  14. #include "ubusd.h"
  15. static struct avl_tree patterns;
  16. static struct ubus_object *event_obj;
  17. static int event_seq = 0;
  18. static int obj_event_seq = 1;
  19. struct event_source {
  20. struct list_head list;
  21. struct ubus_object *obj;
  22. struct avl_node avl;
  23. bool partial;
  24. };
  25. static void ubusd_delete_event_source(struct event_source *evs)
  26. {
  27. list_del(&evs->list);
  28. avl_delete(&patterns, &evs->avl);
  29. free(evs);
  30. }
  31. void ubusd_event_cleanup_object(struct ubus_object *obj)
  32. {
  33. struct event_source *ev;
  34. while (!list_empty(&obj->events)) {
  35. ev = list_first_entry(&obj->events, struct event_source, list);
  36. ubusd_delete_event_source(ev);
  37. }
  38. }
  39. enum {
  40. EVREG_PATTERN,
  41. EVREG_OBJECT,
  42. EVREG_LAST,
  43. };
  44. static struct blobmsg_policy evr_policy[] = {
  45. [EVREG_PATTERN] = { .name = "pattern", .type = BLOBMSG_TYPE_STRING },
  46. [EVREG_OBJECT] = { .name = "object", .type = BLOBMSG_TYPE_INT32 },
  47. };
  48. static int ubusd_alloc_event_pattern(struct ubus_client *cl, struct blob_attr *msg)
  49. {
  50. struct event_source *ev;
  51. struct ubus_object *obj;
  52. struct blob_attr *attr[EVREG_LAST];
  53. char *pattern, *name;
  54. uint32_t id;
  55. bool partial = false;
  56. int len;
  57. blobmsg_parse(evr_policy, EVREG_LAST, attr, blob_data(msg), blob_len(msg));
  58. if (!attr[EVREG_OBJECT] || !attr[EVREG_PATTERN])
  59. return UBUS_STATUS_INVALID_ARGUMENT;
  60. id = blobmsg_get_u32(attr[EVREG_OBJECT]);
  61. if (id < UBUS_SYSTEM_OBJECT_MAX)
  62. return UBUS_STATUS_PERMISSION_DENIED;
  63. obj = ubusd_find_object(id);
  64. if (!obj)
  65. return UBUS_STATUS_NOT_FOUND;
  66. if (obj->client != cl)
  67. return UBUS_STATUS_PERMISSION_DENIED;
  68. pattern = blobmsg_data(attr[EVREG_PATTERN]);
  69. len = strlen(pattern);
  70. if (pattern[len - 1] == '*') {
  71. partial = true;
  72. pattern[len - 1] = 0;
  73. len--;
  74. }
  75. if (pattern[0] && ubusd_acl_check(cl, pattern, NULL, UBUS_ACL_LISTEN))
  76. return UBUS_STATUS_PERMISSION_DENIED;
  77. ev = calloc(1, sizeof(*ev) + len + 1);
  78. if (!ev)
  79. return UBUS_STATUS_NO_DATA;
  80. list_add(&ev->list, &obj->events);
  81. ev->obj = obj;
  82. ev->partial = partial;
  83. name = (char *) (ev + 1);
  84. strcpy(name, pattern);
  85. ev->avl.key = name;
  86. avl_insert(&patterns, &ev->avl);
  87. return 0;
  88. }
  89. static void ubusd_send_event_msg(struct ubus_msg_buf **ub, struct ubus_client *cl,
  90. struct ubus_object *obj, const char *id,
  91. event_fill_cb fill_cb, void *cb_priv)
  92. {
  93. uint32_t *objid_ptr;
  94. /* do not loop back events */
  95. if (obj->client == cl)
  96. return;
  97. /* do not send duplicate events */
  98. if (obj->event_seen == obj_event_seq)
  99. return;
  100. obj->event_seen = obj_event_seq;
  101. if (!*ub) {
  102. *ub = fill_cb(cb_priv, id);
  103. (*ub)->hdr.type = UBUS_MSG_INVOKE;
  104. (*ub)->hdr.peer = 0;
  105. }
  106. objid_ptr = blob_data(blob_data((*ub)->data));
  107. *objid_ptr = htonl(obj->id.id);
  108. (*ub)->hdr.seq = ++event_seq;
  109. ubus_msg_send(obj->client, *ub);
  110. }
  111. int ubusd_send_event(struct ubus_client *cl, const char *id,
  112. event_fill_cb fill_cb, void *cb_priv)
  113. {
  114. struct ubus_msg_buf *ub = NULL;
  115. struct event_source *ev;
  116. int match_len = 0;
  117. if (ubusd_acl_check(cl, id, NULL, UBUS_ACL_SEND))
  118. return UBUS_STATUS_PERMISSION_DENIED;
  119. obj_event_seq++;
  120. /*
  121. * Since this tree is sorted alphabetically, we can only expect to find
  122. * matching entries as long as the number of matching characters
  123. * between the pattern string and our string is monotonically increasing.
  124. */
  125. avl_for_each_element(&patterns, ev, avl) {
  126. const char *key = ev->avl.key;
  127. int cur_match_len;
  128. bool full_match;
  129. full_match = ubus_strmatch_len(id, key, &cur_match_len);
  130. if (cur_match_len < match_len)
  131. break;
  132. match_len = cur_match_len;
  133. if (!full_match) {
  134. if (!ev->partial)
  135. continue;
  136. if (match_len != (int) strlen(key))
  137. continue;
  138. }
  139. ubusd_send_event_msg(&ub, cl, ev->obj, id, fill_cb, cb_priv);
  140. }
  141. if (ub)
  142. ubus_msg_free(ub);
  143. return 0;
  144. }
  145. enum {
  146. EVMSG_ID,
  147. EVMSG_DATA,
  148. EVMSG_LAST,
  149. };
  150. static struct blobmsg_policy ev_policy[] = {
  151. [EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
  152. [EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
  153. };
  154. static struct ubus_msg_buf *
  155. ubusd_create_event_from_msg(void *priv, const char *id)
  156. {
  157. struct blob_attr *msg = priv;
  158. blob_buf_init(&b, 0);
  159. blob_put_int32(&b, UBUS_ATTR_OBJID, 0);
  160. blob_put_string(&b, UBUS_ATTR_METHOD, id);
  161. blob_put(&b, UBUS_ATTR_DATA, blobmsg_data(msg), blobmsg_data_len(msg));
  162. return ubus_msg_new(b.head, blob_raw_len(b.head), true);
  163. }
  164. static int ubusd_forward_event(struct ubus_client *cl, struct blob_attr *msg)
  165. {
  166. struct blob_attr *data;
  167. struct blob_attr *attr[EVMSG_LAST];
  168. const char *id;
  169. blobmsg_parse(ev_policy, EVMSG_LAST, attr, blob_data(msg), blob_len(msg));
  170. if (!attr[EVMSG_ID] || !attr[EVMSG_DATA])
  171. return UBUS_STATUS_INVALID_ARGUMENT;
  172. id = blobmsg_data(attr[EVMSG_ID]);
  173. data = attr[EVMSG_DATA];
  174. if (!strncmp(id, "ubus.", 5))
  175. return UBUS_STATUS_PERMISSION_DENIED;
  176. return ubusd_send_event(cl, id, ubusd_create_event_from_msg, data);
  177. }
  178. static int ubusd_event_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg)
  179. {
  180. if (!strcmp(method, "register"))
  181. return ubusd_alloc_event_pattern(cl, msg);
  182. if (!strcmp(method, "send"))
  183. return ubusd_forward_event(cl, msg);
  184. return UBUS_STATUS_INVALID_COMMAND;
  185. }
  186. static struct ubus_msg_buf *
  187. ubusd_create_object_event_msg(void *priv, const char *id)
  188. {
  189. struct ubus_object *obj = priv;
  190. void *s;
  191. blob_buf_init(&b, 0);
  192. blob_put_int32(&b, UBUS_ATTR_OBJID, 0);
  193. blob_put_string(&b, UBUS_ATTR_METHOD, id);
  194. s = blob_nest_start(&b, UBUS_ATTR_DATA);
  195. blobmsg_add_u32(&b, "id", obj->id.id);
  196. blobmsg_add_string(&b, "path", obj->path.key);
  197. blob_nest_end(&b, s);
  198. return ubus_msg_new(b.head, blob_raw_len(b.head), true);
  199. }
  200. void ubusd_send_obj_event(struct ubus_object *obj, bool add)
  201. {
  202. const char *id = add ? "ubus.object.add" : "ubus.object.remove";
  203. ubusd_send_event(NULL, id, ubusd_create_object_event_msg, obj);
  204. }
  205. void ubusd_event_init(void)
  206. {
  207. ubus_init_string_tree(&patterns, true);
  208. event_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_EVENT);
  209. if (event_obj != NULL)
  210. event_obj->recv_msg = ubusd_event_recv;
  211. }