ubusd_proto.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. /*
  2. * Copyright (C) 2011-2014 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 <unistd.h>
  15. #include "ubusd.h"
  16. struct blob_buf b;
  17. static struct ubus_msg_buf *retmsg;
  18. static int *retmsg_data;
  19. static struct avl_tree clients;
  20. static struct blob_attr *attrbuf[UBUS_ATTR_MAX];
  21. typedef int (*ubus_cmd_cb)(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr);
  22. static const struct blob_attr_info ubus_policy[UBUS_ATTR_MAX] = {
  23. [UBUS_ATTR_SIGNATURE] = { .type = BLOB_ATTR_NESTED },
  24. [UBUS_ATTR_OBJTYPE] = { .type = BLOB_ATTR_INT32 },
  25. [UBUS_ATTR_OBJPATH] = { .type = BLOB_ATTR_STRING },
  26. [UBUS_ATTR_OBJID] = { .type = BLOB_ATTR_INT32 },
  27. [UBUS_ATTR_STATUS] = { .type = BLOB_ATTR_INT32 },
  28. [UBUS_ATTR_METHOD] = { .type = BLOB_ATTR_STRING },
  29. };
  30. static struct blob_attr **ubus_parse_msg(struct blob_attr *msg)
  31. {
  32. blob_parse(msg, attrbuf, ubus_policy, UBUS_ATTR_MAX);
  33. return attrbuf;
  34. }
  35. static void ubus_msg_close_fd(struct ubus_msg_buf *ub)
  36. {
  37. if (ub->fd < 0)
  38. return;
  39. close(ub->fd);
  40. ub->fd = -1;
  41. }
  42. static void ubus_msg_init(struct ubus_msg_buf *ub, uint8_t type, uint16_t seq, uint32_t peer)
  43. {
  44. ub->hdr.version = 0;
  45. ub->hdr.type = type;
  46. ub->hdr.seq = seq;
  47. ub->hdr.peer = peer;
  48. }
  49. static struct ubus_msg_buf *ubus_msg_from_blob(bool shared)
  50. {
  51. return ubus_msg_new(b.head, blob_raw_len(b.head), shared);
  52. }
  53. static struct ubus_msg_buf *ubus_reply_from_blob(struct ubus_msg_buf *ub, bool shared)
  54. {
  55. struct ubus_msg_buf *new;
  56. new = ubus_msg_from_blob(shared);
  57. if (!new)
  58. return NULL;
  59. ubus_msg_init(new, UBUS_MSG_DATA, ub->hdr.seq, ub->hdr.peer);
  60. return new;
  61. }
  62. static void
  63. ubus_send_msg_from_blob(struct ubus_client *cl, struct ubus_msg_buf *ub,
  64. uint8_t type)
  65. {
  66. ub = ubus_reply_from_blob(ub, true);
  67. if (!ub)
  68. return;
  69. ub->hdr.type = type;
  70. ubus_msg_send(cl, ub, true);
  71. }
  72. static bool ubusd_send_hello(struct ubus_client *cl)
  73. {
  74. struct ubus_msg_buf *ub;
  75. blob_buf_init(&b, 0);
  76. ub = ubus_msg_from_blob(true);
  77. if (!ub)
  78. return false;
  79. ubus_msg_init(ub, UBUS_MSG_HELLO, 0, cl->id.id);
  80. ubus_msg_send(cl, ub, true);
  81. return true;
  82. }
  83. static int ubusd_send_pong(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  84. {
  85. ub->hdr.type = UBUS_MSG_DATA;
  86. ubus_msg_send(cl, ub, false);
  87. return 0;
  88. }
  89. static int ubusd_handle_remove_object(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  90. {
  91. struct ubus_object *obj;
  92. if (!attr[UBUS_ATTR_OBJID])
  93. return UBUS_STATUS_INVALID_ARGUMENT;
  94. obj = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_OBJID]));
  95. if (!obj)
  96. return UBUS_STATUS_NOT_FOUND;
  97. if (obj->client != cl)
  98. return UBUS_STATUS_PERMISSION_DENIED;
  99. blob_buf_init(&b, 0);
  100. blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
  101. /* check if we're removing the object type as well */
  102. if (obj->type && obj->type->refcount == 1)
  103. blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id.id);
  104. ubusd_free_object(obj);
  105. ubus_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
  106. return 0;
  107. }
  108. static int ubusd_handle_add_object(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  109. {
  110. struct ubus_object *obj;
  111. obj = ubusd_create_object(cl, attr);
  112. if (!obj)
  113. return UBUS_STATUS_INVALID_ARGUMENT;
  114. blob_buf_init(&b, 0);
  115. blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
  116. if (attr[UBUS_ATTR_SIGNATURE])
  117. blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id.id);
  118. ubus_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
  119. return 0;
  120. }
  121. static void ubusd_send_obj(struct ubus_client *cl, struct ubus_msg_buf *ub, struct ubus_object *obj)
  122. {
  123. struct ubus_method *m;
  124. void *s;
  125. blob_buf_init(&b, 0);
  126. blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->path.key);
  127. blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
  128. blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id.id);
  129. s = blob_nest_start(&b, UBUS_ATTR_SIGNATURE);
  130. list_for_each_entry(m, &obj->type->methods, list)
  131. blobmsg_add_blob(&b, m->data);
  132. blob_nest_end(&b, s);
  133. ubus_send_msg_from_blob(cl, ub, UBUS_MSG_DATA);
  134. }
  135. static int ubusd_handle_lookup(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  136. {
  137. struct ubus_object *obj;
  138. char *objpath;
  139. bool found = false;
  140. int len;
  141. if (!attr[UBUS_ATTR_OBJPATH]) {
  142. avl_for_each_element(&path, obj, path)
  143. ubusd_send_obj(cl, ub, obj);
  144. return 0;
  145. }
  146. objpath = blob_data(attr[UBUS_ATTR_OBJPATH]);
  147. len = strlen(objpath);
  148. if (objpath[len - 1] != '*') {
  149. obj = avl_find_element(&path, objpath, obj, path);
  150. if (!obj)
  151. return UBUS_STATUS_NOT_FOUND;
  152. ubusd_send_obj(cl, ub, obj);
  153. return 0;
  154. }
  155. objpath[--len] = 0;
  156. obj = avl_find_ge_element(&path, objpath, obj, path);
  157. if (!obj)
  158. return UBUS_STATUS_NOT_FOUND;
  159. while (!strncmp(objpath, obj->path.key, len)) {
  160. found = true;
  161. ubusd_send_obj(cl, ub, obj);
  162. if (obj == avl_last_element(&path, obj, path))
  163. break;
  164. obj = avl_next_element(obj, path);
  165. }
  166. if (!found)
  167. return UBUS_STATUS_NOT_FOUND;
  168. return 0;
  169. }
  170. static void
  171. ubusd_forward_invoke(struct ubus_object *obj, const char *method,
  172. struct ubus_msg_buf *ub, struct blob_attr *data)
  173. {
  174. blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
  175. blob_put_string(&b, UBUS_ATTR_METHOD, method);
  176. if (data)
  177. blob_put(&b, UBUS_ATTR_DATA, blob_data(data), blob_len(data));
  178. ubus_send_msg_from_blob(obj->client, ub, UBUS_MSG_INVOKE);
  179. }
  180. static int ubusd_handle_invoke(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  181. {
  182. struct ubus_object *obj = NULL;
  183. struct ubus_id *id;
  184. const char *method;
  185. if (!attr[UBUS_ATTR_METHOD] || !attr[UBUS_ATTR_OBJID])
  186. return UBUS_STATUS_INVALID_ARGUMENT;
  187. id = ubus_find_id(&objects, blob_get_u32(attr[UBUS_ATTR_OBJID]));
  188. if (!id)
  189. return UBUS_STATUS_NOT_FOUND;
  190. obj = container_of(id, struct ubus_object, id);
  191. method = blob_data(attr[UBUS_ATTR_METHOD]);
  192. if (!obj->client)
  193. return obj->recv_msg(cl, ub, method, attr[UBUS_ATTR_DATA]);
  194. ub->hdr.peer = cl->id.id;
  195. blob_buf_init(&b, 0);
  196. ubusd_forward_invoke(obj, method, ub, attr[UBUS_ATTR_DATA]);
  197. ubus_msg_free(ub);
  198. return -1;
  199. }
  200. static int ubusd_handle_notify(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  201. {
  202. struct ubus_object *obj = NULL;
  203. struct ubus_subscription *s;
  204. struct ubus_id *id;
  205. const char *method;
  206. bool no_reply = false;
  207. void *c;
  208. if (!attr[UBUS_ATTR_METHOD] || !attr[UBUS_ATTR_OBJID])
  209. return UBUS_STATUS_INVALID_ARGUMENT;
  210. if (attr[UBUS_ATTR_NO_REPLY])
  211. no_reply = blob_get_int8(attr[UBUS_ATTR_NO_REPLY]);
  212. id = ubus_find_id(&objects, blob_get_u32(attr[UBUS_ATTR_OBJID]));
  213. if (!id)
  214. return UBUS_STATUS_NOT_FOUND;
  215. obj = container_of(id, struct ubus_object, id);
  216. if (obj->client != cl)
  217. return UBUS_STATUS_PERMISSION_DENIED;
  218. if (!no_reply) {
  219. blob_buf_init(&b, 0);
  220. blob_put_int32(&b, UBUS_ATTR_OBJID, id->id);
  221. c = blob_nest_start(&b, UBUS_ATTR_SUBSCRIBERS);
  222. list_for_each_entry(s, &obj->subscribers, list) {
  223. blob_put_int32(&b, 0, s->subscriber->id.id);
  224. }
  225. blob_nest_end(&b, c);
  226. blob_put_int32(&b, UBUS_ATTR_STATUS, 0);
  227. ubus_send_msg_from_blob(cl, ub, UBUS_MSG_STATUS);
  228. }
  229. ub->hdr.peer = cl->id.id;
  230. method = blob_data(attr[UBUS_ATTR_METHOD]);
  231. list_for_each_entry(s, &obj->subscribers, list) {
  232. blob_buf_init(&b, 0);
  233. if (no_reply)
  234. blob_put_int8(&b, UBUS_ATTR_NO_REPLY, 1);
  235. ubusd_forward_invoke(s->subscriber, method, ub, attr[UBUS_ATTR_DATA]);
  236. }
  237. ubus_msg_free(ub);
  238. return -1;
  239. }
  240. static struct ubus_client *ubusd_get_client_by_id(uint32_t id)
  241. {
  242. struct ubus_id *clid;
  243. clid = ubus_find_id(&clients, id);
  244. if (!clid)
  245. return NULL;
  246. return container_of(clid, struct ubus_client, id);
  247. }
  248. static int ubusd_handle_response(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  249. {
  250. struct ubus_object *obj;
  251. if (!attr[UBUS_ATTR_OBJID] ||
  252. (ub->hdr.type == UBUS_MSG_STATUS && !attr[UBUS_ATTR_STATUS]) ||
  253. (ub->hdr.type == UBUS_MSG_DATA && !attr[UBUS_ATTR_DATA]))
  254. goto error;
  255. obj = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_OBJID]));
  256. if (!obj)
  257. goto error;
  258. if (cl != obj->client)
  259. goto error;
  260. cl = ubusd_get_client_by_id(ub->hdr.peer);
  261. if (!cl)
  262. goto error;
  263. ub->hdr.peer = blob_get_u32(attr[UBUS_ATTR_OBJID]);
  264. ubus_msg_send(cl, ub, true);
  265. return -1;
  266. error:
  267. ubus_msg_free(ub);
  268. return -1;
  269. }
  270. static int ubusd_handle_add_watch(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  271. {
  272. struct ubus_object *obj, *target;
  273. if (!attr[UBUS_ATTR_OBJID] || !attr[UBUS_ATTR_TARGET])
  274. return UBUS_STATUS_INVALID_ARGUMENT;
  275. obj = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_OBJID]));
  276. if (!obj)
  277. return UBUS_STATUS_NOT_FOUND;
  278. if (cl != obj->client)
  279. return UBUS_STATUS_INVALID_ARGUMENT;
  280. target = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_TARGET]));
  281. if (!target)
  282. return UBUS_STATUS_NOT_FOUND;
  283. if (cl == target->client)
  284. return UBUS_STATUS_INVALID_ARGUMENT;
  285. ubus_subscribe(obj, target);
  286. return 0;
  287. }
  288. static int ubusd_handle_remove_watch(struct ubus_client *cl, struct ubus_msg_buf *ub, struct blob_attr **attr)
  289. {
  290. struct ubus_object *obj;
  291. struct ubus_subscription *s;
  292. uint32_t id;
  293. if (!attr[UBUS_ATTR_OBJID] || !attr[UBUS_ATTR_TARGET])
  294. return UBUS_STATUS_INVALID_ARGUMENT;
  295. obj = ubusd_find_object(blob_get_u32(attr[UBUS_ATTR_OBJID]));
  296. if (!obj)
  297. return UBUS_STATUS_NOT_FOUND;
  298. if (cl != obj->client)
  299. return UBUS_STATUS_INVALID_ARGUMENT;
  300. id = blob_get_u32(attr[UBUS_ATTR_TARGET]);
  301. list_for_each_entry(s, &obj->target_list, target_list) {
  302. if (s->target->id.id != id)
  303. continue;
  304. ubus_unsubscribe(s);
  305. return 0;
  306. }
  307. return UBUS_STATUS_NOT_FOUND;
  308. }
  309. static const ubus_cmd_cb handlers[__UBUS_MSG_LAST] = {
  310. [UBUS_MSG_PING] = ubusd_send_pong,
  311. [UBUS_MSG_ADD_OBJECT] = ubusd_handle_add_object,
  312. [UBUS_MSG_REMOVE_OBJECT] = ubusd_handle_remove_object,
  313. [UBUS_MSG_LOOKUP] = ubusd_handle_lookup,
  314. [UBUS_MSG_INVOKE] = ubusd_handle_invoke,
  315. [UBUS_MSG_STATUS] = ubusd_handle_response,
  316. [UBUS_MSG_DATA] = ubusd_handle_response,
  317. [UBUS_MSG_SUBSCRIBE] = ubusd_handle_add_watch,
  318. [UBUS_MSG_UNSUBSCRIBE] = ubusd_handle_remove_watch,
  319. [UBUS_MSG_NOTIFY] = ubusd_handle_notify,
  320. };
  321. void ubusd_proto_receive_message(struct ubus_client *cl, struct ubus_msg_buf *ub)
  322. {
  323. ubus_cmd_cb cb = NULL;
  324. int ret;
  325. retmsg->hdr.seq = ub->hdr.seq;
  326. retmsg->hdr.peer = ub->hdr.peer;
  327. if (ub->hdr.type < __UBUS_MSG_LAST)
  328. cb = handlers[ub->hdr.type];
  329. if (ub->hdr.type != UBUS_MSG_STATUS)
  330. ubus_msg_close_fd(ub);
  331. if (cb)
  332. ret = cb(cl, ub, ubus_parse_msg(ub->data));
  333. else
  334. ret = UBUS_STATUS_INVALID_COMMAND;
  335. if (ret == -1)
  336. return;
  337. ubus_msg_free(ub);
  338. *retmsg_data = htonl(ret);
  339. ubus_msg_send(cl, retmsg, false);
  340. }
  341. struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb)
  342. {
  343. struct ubus_client *cl;
  344. cl = calloc(1, sizeof(*cl));
  345. if (!cl)
  346. return NULL;
  347. INIT_LIST_HEAD(&cl->objects);
  348. cl->sock.fd = fd;
  349. cl->sock.cb = cb;
  350. cl->pending_msg_fd = -1;
  351. if (!ubus_alloc_id(&clients, &cl->id, 0))
  352. goto free;
  353. if (!ubusd_send_hello(cl))
  354. goto delete;
  355. return cl;
  356. delete:
  357. ubus_free_id(&clients, &cl->id);
  358. free:
  359. free(cl);
  360. return NULL;
  361. }
  362. void ubusd_proto_free_client(struct ubus_client *cl)
  363. {
  364. struct ubus_object *obj;
  365. while (!list_empty(&cl->objects)) {
  366. obj = list_first_entry(&cl->objects, struct ubus_object, list);
  367. ubusd_free_object(obj);
  368. }
  369. ubus_free_id(&clients, &cl->id);
  370. }
  371. void ubus_notify_subscription(struct ubus_object *obj)
  372. {
  373. bool active = !list_empty(&obj->subscribers);
  374. struct ubus_msg_buf *ub;
  375. blob_buf_init(&b, 0);
  376. blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id.id);
  377. blob_put_int8(&b, UBUS_ATTR_ACTIVE, active);
  378. ub = ubus_msg_from_blob(false);
  379. if (!ub)
  380. return;
  381. ubus_msg_init(ub, UBUS_MSG_NOTIFY, ++obj->invoke_seq, 0);
  382. ubus_msg_send(obj->client, ub, true);
  383. }
  384. void ubus_notify_unsubscribe(struct ubus_subscription *s)
  385. {
  386. struct ubus_msg_buf *ub;
  387. blob_buf_init(&b, 0);
  388. blob_put_int32(&b, UBUS_ATTR_OBJID, s->subscriber->id.id);
  389. blob_put_int32(&b, UBUS_ATTR_TARGET, s->target->id.id);
  390. ub = ubus_msg_from_blob(false);
  391. if (ub != NULL) {
  392. ubus_msg_init(ub, UBUS_MSG_UNSUBSCRIBE, ++s->subscriber->invoke_seq, 0);
  393. ubus_msg_send(s->subscriber->client, ub, true);
  394. }
  395. ubus_unsubscribe(s);
  396. }
  397. static void __constructor ubusd_proto_init(void)
  398. {
  399. ubus_init_id_tree(&clients);
  400. blob_buf_init(&b, 0);
  401. blob_put_int32(&b, UBUS_ATTR_STATUS, 0);
  402. retmsg = ubus_msg_from_blob(false);
  403. if (!retmsg)
  404. exit(1);
  405. retmsg->hdr.type = UBUS_MSG_STATUS;
  406. retmsg_data = blob_data(blob_data(retmsg->data));
  407. }