libubus-obj.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Copyright (C) 2011-2012 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 <unistd.h>
  14. #include "libubus.h"
  15. #include "libubus-internal.h"
  16. static void
  17. ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr,
  18. struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
  19. {
  20. struct ubus_subscriber *s;
  21. if (!obj || !attrbuf[UBUS_ATTR_TARGET])
  22. return;
  23. if (obj->methods != &watch_method)
  24. return;
  25. s = container_of(obj, struct ubus_subscriber, obj);
  26. if (s->remove_cb)
  27. s->remove_cb(ctx, s, blob_get_u32(attrbuf[UBUS_ATTR_TARGET]));
  28. if (fd >= 0)
  29. close(fd);
  30. }
  31. static void
  32. ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr,
  33. struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
  34. {
  35. if (!obj || !attrbuf[UBUS_ATTR_ACTIVE])
  36. return;
  37. obj->has_subscribers = blob_get_u8(attrbuf[UBUS_ATTR_ACTIVE]);
  38. if (obj->subscribe_cb)
  39. obj->subscribe_cb(ctx, obj);
  40. if (fd >= 0)
  41. close(fd);
  42. }
  43. static void
  44. ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr,
  45. struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
  46. {
  47. struct ubus_request_data req = {
  48. .fd = -1,
  49. .req_fd = fd,
  50. };
  51. int method;
  52. int ret;
  53. bool no_reply = false;
  54. if (!obj) {
  55. ret = UBUS_STATUS_NOT_FOUND;
  56. goto send;
  57. }
  58. if (!attrbuf[UBUS_ATTR_METHOD]) {
  59. ret = UBUS_STATUS_INVALID_ARGUMENT;
  60. goto send;
  61. }
  62. if (attrbuf[UBUS_ATTR_NO_REPLY])
  63. no_reply = blob_get_int8(attrbuf[UBUS_ATTR_NO_REPLY]);
  64. req.peer = hdr->peer;
  65. req.seq = hdr->seq;
  66. req.object = obj->id;
  67. if (attrbuf[UBUS_ATTR_USER] && attrbuf[UBUS_ATTR_GROUP]) {
  68. req.acl.user = blobmsg_get_string(attrbuf[UBUS_ATTR_USER]);
  69. req.acl.group = blobmsg_get_string(attrbuf[UBUS_ATTR_GROUP]);
  70. req.acl.object = obj->name;
  71. }
  72. for (method = 0; method < obj->n_methods; method++)
  73. if (!obj->methods[method].name ||
  74. !strcmp(obj->methods[method].name,
  75. blob_data(attrbuf[UBUS_ATTR_METHOD])))
  76. goto found;
  77. /* not found */
  78. ret = UBUS_STATUS_METHOD_NOT_FOUND;
  79. goto send;
  80. found:
  81. if (!attrbuf[UBUS_ATTR_DATA]) {
  82. ret = UBUS_STATUS_INVALID_ARGUMENT;
  83. goto send;
  84. }
  85. ret = obj->methods[method].handler(ctx, obj, &req,
  86. blob_data(attrbuf[UBUS_ATTR_METHOD]),
  87. attrbuf[UBUS_ATTR_DATA]);
  88. if (req.req_fd >= 0)
  89. close(req.req_fd);
  90. if (req.deferred || no_reply)
  91. return;
  92. send:
  93. ubus_complete_deferred_request(ctx, &req, ret);
  94. }
  95. void __hidden ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd)
  96. {
  97. void (*cb)(struct ubus_context *, struct ubus_msghdr *,
  98. struct ubus_object *, struct blob_attr **, int fd);
  99. struct ubus_msghdr *hdr = &buf->hdr;
  100. struct blob_attr **attrbuf;
  101. struct ubus_object *obj;
  102. uint32_t objid;
  103. void *prev_data = NULL;
  104. attrbuf = ubus_parse_msg(buf->data, blob_raw_len(buf->data));
  105. if (!attrbuf[UBUS_ATTR_OBJID])
  106. return;
  107. objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
  108. obj = avl_find_element(&ctx->objects, &objid, obj, avl);
  109. switch (hdr->type) {
  110. case UBUS_MSG_INVOKE:
  111. cb = ubus_process_invoke;
  112. break;
  113. case UBUS_MSG_UNSUBSCRIBE:
  114. cb = ubus_process_unsubscribe;
  115. break;
  116. case UBUS_MSG_NOTIFY:
  117. cb = ubus_process_notify;
  118. break;
  119. default:
  120. return;
  121. }
  122. if (buf == &ctx->msgbuf) {
  123. prev_data = buf->data;
  124. buf->data = NULL;
  125. }
  126. cb(ctx, hdr, obj, attrbuf, fd);
  127. if (prev_data) {
  128. if (buf->data)
  129. free(prev_data);
  130. else
  131. buf->data = prev_data;
  132. }
  133. }
  134. static void ubus_add_object_cb(struct ubus_request *req, int type, struct blob_attr *msg)
  135. {
  136. struct ubus_object *obj = req->priv;
  137. struct blob_attr **attrbuf = ubus_parse_msg(msg, blob_raw_len(msg));
  138. if (!attrbuf[UBUS_ATTR_OBJID])
  139. return;
  140. obj->id = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
  141. if (attrbuf[UBUS_ATTR_OBJTYPE])
  142. obj->type->id = blob_get_u32(attrbuf[UBUS_ATTR_OBJTYPE]);
  143. obj->avl.key = &obj->id;
  144. avl_insert(&req->ctx->objects, &obj->avl);
  145. }
  146. static void ubus_push_method_data(const struct ubus_method *m)
  147. {
  148. void *mtbl;
  149. int i;
  150. mtbl = blobmsg_open_table(&b, m->name);
  151. for (i = 0; i < m->n_policy; i++) {
  152. if (m->mask && !(m->mask & (1 << i)))
  153. continue;
  154. blobmsg_add_u32(&b, m->policy[i].name, m->policy[i].type);
  155. }
  156. blobmsg_close_table(&b, mtbl);
  157. }
  158. static bool ubus_push_object_type(const struct ubus_object_type *type)
  159. {
  160. void *s;
  161. int i;
  162. s = blob_nest_start(&b, UBUS_ATTR_SIGNATURE);
  163. for (i = 0; i < type->n_methods; i++)
  164. ubus_push_method_data(&type->methods[i]);
  165. blob_nest_end(&b, s);
  166. return true;
  167. }
  168. int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj)
  169. {
  170. struct ubus_request req;
  171. int ret;
  172. blob_buf_init(&b, 0);
  173. if (obj->name && obj->type) {
  174. blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->name);
  175. if (obj->type->id)
  176. blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id);
  177. else if (!ubus_push_object_type(obj->type))
  178. return UBUS_STATUS_INVALID_ARGUMENT;
  179. }
  180. if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_ADD_OBJECT, 0) < 0)
  181. return UBUS_STATUS_INVALID_ARGUMENT;
  182. req.raw_data_cb = ubus_add_object_cb;
  183. req.priv = obj;
  184. ret = ubus_complete_request(ctx, &req, 0);
  185. if (ret)
  186. return ret;
  187. if (!obj->id)
  188. return UBUS_STATUS_NO_DATA;
  189. return 0;
  190. }
  191. static void ubus_remove_object_cb(struct ubus_request *req, int type, struct blob_attr *msg)
  192. {
  193. struct ubus_object *obj = req->priv;
  194. struct blob_attr **attrbuf = ubus_parse_msg(msg, blob_raw_len(msg));
  195. if (!attrbuf[UBUS_ATTR_OBJID])
  196. return;
  197. avl_delete(&req->ctx->objects, &obj->avl);
  198. obj->id = 0;
  199. if (attrbuf[UBUS_ATTR_OBJTYPE] && obj->type)
  200. obj->type->id = 0;
  201. }
  202. int ubus_remove_object(struct ubus_context *ctx, struct ubus_object *obj)
  203. {
  204. struct ubus_request req;
  205. int ret;
  206. blob_buf_init(&b, 0);
  207. blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id);
  208. if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_REMOVE_OBJECT, 0) < 0)
  209. return UBUS_STATUS_INVALID_ARGUMENT;
  210. req.raw_data_cb = ubus_remove_object_cb;
  211. req.priv = obj;
  212. ret = ubus_complete_request(ctx, &req, 0);
  213. if (ret)
  214. return ret;
  215. if (obj->id)
  216. return UBUS_STATUS_NO_DATA;
  217. return 0;
  218. }