ubusd_event.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. ev = calloc(1, sizeof(*ev) + len + 1);
  76. if (!ev)
  77. return UBUS_STATUS_NO_DATA;
  78. list_add(&ev->list, &obj->events);
  79. ev->obj = obj;
  80. ev->partial = partial;
  81. name = (char *) (ev + 1);
  82. strcpy(name, pattern);
  83. ev->avl.key = name;
  84. avl_insert(&patterns, &ev->avl);
  85. return 0;
  86. }
  87. static void ubusd_send_event_msg(struct ubus_msg_buf **ub, struct ubus_client *cl,
  88. struct ubus_object *obj, const char *id,
  89. event_fill_cb fill_cb, void *cb_priv)
  90. {
  91. uint32_t *objid_ptr;
  92. /* do not loop back events */
  93. if (obj->client == cl)
  94. return;
  95. /* do not send duplicate events */
  96. if (obj->event_seen == obj_event_seq)
  97. return;
  98. obj->event_seen = obj_event_seq;
  99. if (!*ub) {
  100. *ub = fill_cb(cb_priv, id);
  101. (*ub)->hdr.type = UBUS_MSG_INVOKE;
  102. (*ub)->hdr.peer = 0;
  103. }
  104. objid_ptr = blob_data(blob_data((*ub)->data));
  105. *objid_ptr = htonl(obj->id.id);
  106. (*ub)->hdr.seq = ++event_seq;
  107. ubus_msg_send(obj->client, *ub, false);
  108. }
  109. static bool strmatch_len(const char *s1, const char *s2, int *len)
  110. {
  111. for (*len = 0; s1[*len] == s2[*len]; (*len)++)
  112. if (!s1[*len])
  113. return true;
  114. return false;
  115. }
  116. int ubusd_send_event(struct ubus_client *cl, const char *id,
  117. event_fill_cb fill_cb, void *cb_priv)
  118. {
  119. struct ubus_msg_buf *ub = NULL;
  120. struct event_source *ev;
  121. int match_len = 0;
  122. obj_event_seq++;
  123. /*
  124. * Since this tree is sorted alphabetically, we can only expect to find
  125. * matching entries as long as the number of matching characters
  126. * between the pattern string and our string is monotonically increasing.
  127. */
  128. avl_for_each_element(&patterns, ev, avl) {
  129. const char *key = ev->avl.key;
  130. int cur_match_len;
  131. bool full_match;
  132. full_match = strmatch_len(id, key, &cur_match_len);
  133. if (cur_match_len < match_len)
  134. break;
  135. match_len = cur_match_len;
  136. if (!full_match) {
  137. if (!ev->partial)
  138. continue;
  139. if (match_len != strlen(key))
  140. continue;
  141. }
  142. ubusd_send_event_msg(&ub, cl, ev->obj, id, fill_cb, cb_priv);
  143. }
  144. if (ub)
  145. ubus_msg_free(ub);
  146. return 0;
  147. }
  148. enum {
  149. EVMSG_ID,
  150. EVMSG_DATA,
  151. EVMSG_LAST,
  152. };
  153. static struct blobmsg_policy ev_policy[] = {
  154. [EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
  155. [EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
  156. };
  157. static struct ubus_msg_buf *
  158. ubusd_create_event_from_msg(void *priv, const char *id)
  159. {
  160. struct blob_attr *msg = priv;
  161. blob_buf_init(&b, 0);
  162. blob_put_int32(&b, UBUS_ATTR_OBJID, 0);
  163. blob_put_string(&b, UBUS_ATTR_METHOD, id);
  164. blob_put(&b, UBUS_ATTR_DATA, blobmsg_data(msg), blobmsg_data_len(msg));
  165. return ubus_msg_new(b.head, blob_raw_len(b.head), true);
  166. }
  167. static int ubusd_forward_event(struct ubus_client *cl, struct blob_attr *msg)
  168. {
  169. struct blob_attr *data;
  170. struct blob_attr *attr[EVMSG_LAST];
  171. const char *id;
  172. blobmsg_parse(ev_policy, EVMSG_LAST, attr, blob_data(msg), blob_len(msg));
  173. if (!attr[EVMSG_ID] || !attr[EVMSG_DATA])
  174. return UBUS_STATUS_INVALID_ARGUMENT;
  175. id = blobmsg_data(attr[EVMSG_ID]);
  176. data = attr[EVMSG_DATA];
  177. if (!strncmp(id, "ubus.", 5))
  178. return UBUS_STATUS_PERMISSION_DENIED;
  179. return ubusd_send_event(cl, id, ubusd_create_event_from_msg, data);
  180. }
  181. static int ubusd_event_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg)
  182. {
  183. if (!strcmp(method, "register"))
  184. return ubusd_alloc_event_pattern(cl, msg);
  185. if (!strcmp(method, "send"))
  186. return ubusd_forward_event(cl, msg);
  187. return UBUS_STATUS_INVALID_COMMAND;
  188. }
  189. static struct ubus_msg_buf *
  190. ubusd_create_object_event_msg(void *priv, const char *id)
  191. {
  192. struct ubus_object *obj = priv;
  193. void *s;
  194. blob_buf_init(&b, 0);
  195. blob_put_int32(&b, UBUS_ATTR_OBJID, 0);
  196. blob_put_string(&b, UBUS_ATTR_METHOD, id);
  197. s = blob_nest_start(&b, UBUS_ATTR_DATA);
  198. blobmsg_add_u32(&b, "id", obj->id.id);
  199. blobmsg_add_string(&b, "path", obj->path.key);
  200. blob_nest_end(&b, s);
  201. return ubus_msg_new(b.head, blob_raw_len(b.head), true);
  202. }
  203. void ubusd_send_obj_event(struct ubus_object *obj, bool add)
  204. {
  205. const char *id = add ? "ubus.object.add" : "ubus.object.remove";
  206. ubusd_send_event(NULL, id, ubusd_create_object_event_msg, obj);
  207. }
  208. void ubusd_event_init(void)
  209. {
  210. ubus_init_string_tree(&patterns, true);
  211. event_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_EVENT);
  212. if (event_obj != NULL)
  213. event_obj->recv_msg = ubusd_event_recv;
  214. }