add functionality for registering anonymous objects as event listeners
[project/ubus.git] / libubus.c
1 #include <sys/types.h>
2 #include <sys/uio.h>
3 #include <sys/socket.h>
4 #include <unistd.h>
5
6 #include <libubox/blob.h>
7 #include <libubox/blobmsg.h>
8 #include <libubox/usock.h>
9
10 #include "libubus.h"
11 #include "ubusmsg.h"
12
13 #define DEBUG 1
14
15 #ifdef DEBUG
16 #define DPRINTF(_format, ...) fprintf(stderr, "ubus: " _format, ## __VA_ARGS__)
17 #else
18 #define DPRINTF(...) do {} while(0)
19 #endif
20
21 #define STATIC_IOV(_var) { .iov_base = (char *) &(_var), .iov_len = sizeof(_var) }
22
23 const char *__ubus_strerror[__UBUS_STATUS_LAST] = {
24 [UBUS_STATUS_OK] = "Success",
25 [UBUS_STATUS_INVALID_COMMAND] = "Invalid command",
26 [UBUS_STATUS_INVALID_ARGUMENT] = "Invalid argument",
27 [UBUS_STATUS_METHOD_NOT_FOUND] = "Method not found",
28 [UBUS_STATUS_NOT_FOUND] = "Not found",
29 [UBUS_STATUS_NO_DATA] = "No response",
30 [UBUS_STATUS_PERMISSION_DENIED] = "Permission denied",
31 };
32
33 static struct blob_buf b;
34
35 static const struct blob_attr_info ubus_policy[UBUS_ATTR_MAX] = {
36 [UBUS_ATTR_STATUS] = { .type = BLOB_ATTR_INT32 },
37 [UBUS_ATTR_OBJID] = { .type = BLOB_ATTR_INT32 },
38 [UBUS_ATTR_OBJPATH] = { .type = BLOB_ATTR_STRING },
39 [UBUS_ATTR_METHOD] = { .type = BLOB_ATTR_STRING },
40 };
41 static struct blob_attr *attrbuf[UBUS_ATTR_MAX];
42
43 struct ubus_pending_data {
44 struct list_head list;
45 int type;
46 struct blob_attr data[];
47 };
48
49 static int ubus_cmp_id(const void *k1, const void *k2, void *ptr)
50 {
51 const uint32_t *id1 = k1, *id2 = k2;
52
53 if (*id1 < *id2)
54 return -1;
55 else
56 return *id1 > *id2;
57 }
58
59 static struct blob_attr **ubus_parse_msg(struct blob_attr *msg)
60 {
61 blob_parse(msg, attrbuf, ubus_policy, UBUS_ATTR_MAX);
62 return attrbuf;
63 }
64
65 const char *ubus_strerror(int error)
66 {
67 static char err[32];
68
69 if (error < 0 || error >= __UBUS_STATUS_LAST)
70 goto out;
71
72 if (!__ubus_strerror[error])
73 goto out;
74
75 return __ubus_strerror[error];
76
77 out:
78 sprintf(err, "Unknown error: %d", error);
79 return err;
80 }
81
82 static int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
83 struct blob_attr *msg, int cmd, uint32_t peer)
84 {
85 struct ubus_msghdr hdr;
86 struct iovec iov[2] = {
87 STATIC_IOV(hdr)
88 };
89
90 hdr.version = 0;
91 hdr.type = cmd;
92 hdr.seq = seq;
93 hdr.peer = peer;
94
95 if (!msg) {
96 blob_buf_init(&b, 0);
97 msg = b.head;
98 }
99
100 iov[1].iov_base = (char *) msg;
101 iov[1].iov_len = blob_raw_len(msg);
102
103 return writev(ctx->sock.fd, iov, 2);
104 }
105
106 static int ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
107 struct blob_attr *msg, int cmd, uint32_t peer)
108 {
109 memset(req, 0, sizeof(*req));
110
111 INIT_LIST_HEAD(&req->list);
112 INIT_LIST_HEAD(&req->pending);
113 req->ctx = ctx;
114 req->peer = peer;
115 req->seq = ++ctx->request_seq;
116 return ubus_send_msg(ctx, req->seq, msg, cmd, peer);
117 }
118
119 static bool recv_retry(int fd, struct iovec *iov, bool wait)
120 {
121 int bytes;
122
123 while (iov->iov_len > 0) {
124 bytes = read(fd, iov->iov_base, iov->iov_len);
125 if (bytes < 0) {
126 bytes = 0;
127 if (errno == EINTR)
128 continue;
129
130 if (errno != EAGAIN) {
131 perror("read");
132 return false;
133 }
134 }
135 if (!wait && !bytes)
136 return false;
137
138 wait = true;
139 iov->iov_len -= bytes;
140 iov->iov_base += bytes;
141 }
142
143 return true;
144 }
145
146 static bool ubus_validate_hdr(struct ubus_msghdr *hdr)
147 {
148 if (hdr->version != 0)
149 return false;
150
151 if (blob_raw_len(hdr->data) < sizeof(*hdr->data))
152 return false;
153
154 if (blob_raw_len(hdr->data) + sizeof(*hdr) > UBUS_MAX_MSGLEN)
155 return false;
156
157 return true;
158 }
159
160 static bool get_next_msg(struct ubus_context *ctx, bool wait)
161 {
162 struct iovec iov = STATIC_IOV(ctx->msgbuf.hdr);
163
164 /* receive header + start attribute */
165 iov.iov_len += sizeof(struct blob_attr);
166 if (!recv_retry(ctx->sock.fd, &iov, wait))
167 return false;
168
169 iov.iov_len = blob_len(ctx->msgbuf.hdr.data);
170 if (iov.iov_len > 0 && !recv_retry(ctx->sock.fd, &iov, true))
171 return false;
172
173 return ubus_validate_hdr(&ctx->msgbuf.hdr);
174 }
175
176 static bool ubus_get_status(struct ubus_msghdr *hdr, int *ret)
177 {
178 ubus_parse_msg(hdr->data);
179
180 if (!attrbuf[UBUS_ATTR_STATUS])
181 return false;
182
183 *ret = blob_get_int32(attrbuf[UBUS_ATTR_STATUS]);
184 return true;
185 }
186
187 static void req_data_cb(struct ubus_request *req, int type, struct blob_attr *data)
188 {
189 struct blob_attr **attr;
190
191 if (req->raw_data_cb)
192 req->raw_data_cb(req, type, data);
193
194 if (!req->data_cb)
195 return;
196
197 attr = ubus_parse_msg(data);
198 req->data_cb(req, type, attr[UBUS_ATTR_DATA]);
199 }
200
201 static void ubus_process_req_data(struct ubus_request *req)
202 {
203 struct ubus_pending_data *data;
204
205 while (!list_empty(&req->pending)) {
206 data = list_first_entry(&req->pending,
207 struct ubus_pending_data, list);
208 list_del(&data->list);
209 if (!req->cancelled)
210 req_data_cb(req, data->type, data->data);
211 free(data);
212 }
213 }
214
215 static void ubus_req_complete_cb(struct ubus_request *req)
216 {
217 ubus_complete_handler_t cb = req->complete_cb;
218
219 if (!cb)
220 return;
221
222 req->complete_cb = NULL;
223 cb(req, req->status_code);
224 }
225
226 static int ubus_process_req_status(struct ubus_request *req, struct ubus_msghdr *hdr)
227 {
228 int ret = UBUS_STATUS_INVALID_ARGUMENT;
229
230 if (!list_empty(&req->list))
231 list_del(&req->list);
232
233 ubus_get_status(hdr, &ret);
234 req->peer = hdr->peer;
235 req->status_msg = true;
236 req->status_code = ret;
237 if (!req->blocked)
238 ubus_req_complete_cb(req);
239
240 return ret;
241 }
242
243 static void ubus_req_data(struct ubus_request *req, struct ubus_msghdr *hdr)
244 {
245 struct ubus_pending_data *data;
246 int len;
247
248 if (!req->blocked) {
249 req->blocked = true;
250 req_data_cb(req, hdr->type, hdr->data);
251 ubus_process_req_data(req);
252 req->blocked = false;
253
254 if (req->status_msg)
255 ubus_req_complete_cb(req);
256
257 return;
258 }
259
260 len = blob_raw_len(hdr->data);
261 data = calloc(1, sizeof(*data) + len);
262 if (!data)
263 return;
264
265 data->type = hdr->type;
266 memcpy(data->data, hdr->data, len);
267 list_add(&data->list, &req->pending);
268 }
269
270 static struct ubus_request *ubus_find_request(struct ubus_context *ctx, uint32_t seq, uint32_t peer)
271 {
272 struct ubus_request *req;
273
274 list_for_each_entry(req, &ctx->requests, list) {
275 if (seq != req->seq || peer != req->peer)
276 continue;
277
278 return req;
279 }
280 return NULL;
281 }
282
283 static void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr)
284 {
285 struct ubus_request_data req;
286 struct ubus_object *obj;
287 uint32_t objid = 0;
288 int method;
289 int ret = 0;
290
291 ubus_parse_msg(hdr->data);
292
293 if (!attrbuf[UBUS_ATTR_OBJID])
294 return;
295
296 objid = blob_get_int32(attrbuf[UBUS_ATTR_OBJID]);
297
298 if (!attrbuf[UBUS_ATTR_METHOD]) {
299 ret = UBUS_STATUS_INVALID_ARGUMENT;
300 goto send;
301 }
302
303 obj = avl_find_element(&ctx->objects, &objid, obj, avl);
304 if (!obj) {
305 ret = UBUS_STATUS_NOT_FOUND;
306 goto send;
307 }
308
309 for (method = 0; method < obj->n_methods; method++)
310 if (!strcmp(obj->methods[method].name,
311 blob_data(attrbuf[UBUS_ATTR_METHOD])))
312 goto found;
313
314 /* not found */
315 ret = UBUS_STATUS_METHOD_NOT_FOUND;
316 goto send;
317
318 found:
319 req.object = objid;
320 req.peer = hdr->peer;
321 req.seq = hdr->seq;
322 ret = obj->methods[method].handler(ctx, obj, &req,
323 obj->methods[method].name,
324 attrbuf[UBUS_ATTR_DATA]);
325
326 send:
327 blob_buf_init(&b, 0);
328 blob_put_int32(&b, UBUS_ATTR_STATUS, ret);
329 blob_put_int32(&b, UBUS_ATTR_OBJID, objid);
330 ubus_send_msg(ctx, hdr->seq, b.head, UBUS_MSG_STATUS, hdr->peer);
331 }
332
333 static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
334 {
335 struct ubus_request *req;
336
337 switch(hdr->type) {
338 case UBUS_MSG_STATUS:
339 req = ubus_find_request(ctx, hdr->seq, hdr->peer);
340 if (!req)
341 break;
342
343 ubus_process_req_status(req, hdr);
344 break;
345
346 case UBUS_MSG_DATA:
347 req = ubus_find_request(ctx, hdr->seq, hdr->peer);
348 if (req && (req->data_cb || req->raw_data_cb))
349 ubus_req_data(req, hdr);
350 break;
351
352 case UBUS_MSG_INVOKE:
353 ubus_process_invoke(ctx, hdr);
354 break;
355 default:
356 DPRINTF("unknown message type: %d\n", hdr->type);
357 break;
358 }
359 }
360
361 void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req)
362 {
363 if (!list_empty(&req->list))
364 return;
365
366 req->cancelled = true;
367 ubus_process_req_data(req);
368 list_del(&req->list);
369 }
370
371 void ubus_complete_request_async(struct ubus_context *ctx, struct ubus_request *req)
372 {
373 if (!list_empty(&req->list))
374 return;
375
376 list_add(&req->list, &ctx->requests);
377 }
378
379 static void ubus_handle_data(struct uloop_fd *u, unsigned int events)
380 {
381 struct ubus_context *ctx = container_of(u, struct ubus_context, sock);
382 struct ubus_msghdr *hdr = &ctx->msgbuf.hdr;
383
384 while (get_next_msg(ctx, false))
385 ubus_process_msg(ctx, hdr);
386
387 if (u->eof)
388 ctx->connection_lost(ctx);
389 }
390
391 int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req)
392 {
393 struct ubus_msghdr *hdr = &ctx->msgbuf.hdr;
394
395 if (!list_empty(&req->list))
396 list_del(&req->list);
397
398 while (1) {
399 if (req->status_msg)
400 return req->status_code;
401
402 if (req->cancelled)
403 return UBUS_STATUS_NO_DATA;
404
405 if (!get_next_msg(ctx, true))
406 return UBUS_STATUS_NO_DATA;
407
408 if (hdr->seq != req->seq || hdr->peer != req->peer)
409 goto skip;
410
411 switch(hdr->type) {
412 case UBUS_MSG_STATUS:
413 return ubus_process_req_status(req, hdr);
414 case UBUS_MSG_DATA:
415 if (req->data_cb || req->raw_data_cb)
416 ubus_req_data(req, hdr);
417 continue;
418 default:
419 goto skip;
420 }
421
422 skip:
423 ubus_process_msg(ctx, hdr);
424 }
425 }
426
427 struct ubus_lookup_request {
428 struct ubus_request req;
429 ubus_lookup_handler_t cb;
430 };
431
432 static void ubus_lookup_cb(struct ubus_request *ureq, int type, struct blob_attr *msg)
433 {
434 struct ubus_lookup_request *req;
435 struct ubus_object_data obj;
436 struct blob_attr **attr;
437
438 req = container_of(ureq, struct ubus_lookup_request, req);
439 attr = ubus_parse_msg(msg);
440
441 if (!attr[UBUS_ATTR_OBJID] || !attr[UBUS_ATTR_OBJPATH] ||
442 !attr[UBUS_ATTR_OBJTYPE])
443 return;
444
445 memset(&obj, 0, sizeof(obj));
446 obj.id = blob_get_int32(attr[UBUS_ATTR_OBJID]);
447 obj.path = blob_data(attr[UBUS_ATTR_OBJPATH]);
448 obj.type_id = blob_get_int32(attr[UBUS_ATTR_OBJTYPE]);
449 obj.signature = attr[UBUS_ATTR_SIGNATURE];
450 req->cb(ureq->ctx, &obj, ureq->priv);
451 }
452
453 int ubus_lookup(struct ubus_context *ctx, const char *path,
454 ubus_lookup_handler_t cb, void *priv)
455 {
456 struct ubus_lookup_request lookup;
457
458 blob_buf_init(&b, 0);
459 if (path)
460 blob_put_string(&b, UBUS_ATTR_OBJPATH, path);
461 ubus_start_request(ctx, &lookup.req, b.head, UBUS_MSG_LOOKUP, 0);
462 lookup.req.raw_data_cb = ubus_lookup_cb;
463 lookup.req.priv = priv;
464 lookup.cb = cb;
465 return ubus_complete_request(ctx, &lookup.req);
466 }
467
468 static void ubus_lookup_id_cb(struct ubus_request *req, int type, struct blob_attr *msg)
469 {
470 struct blob_attr **attr;
471 uint32_t *id = req->priv;
472
473 attr = ubus_parse_msg(msg);
474
475 if (!attr[UBUS_ATTR_OBJID])
476 return;
477
478 *id = blob_get_int32(attr[UBUS_ATTR_OBJID]);
479 }
480
481 int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id)
482 {
483 struct ubus_request req;
484
485 blob_buf_init(&b, 0);
486 if (path)
487 blob_put_string(&b, UBUS_ATTR_OBJPATH, path);
488 ubus_start_request(ctx, &req, b.head, UBUS_MSG_LOOKUP, 0);
489 req.raw_data_cb = ubus_lookup_id_cb;
490 req.priv = id;
491
492 return ubus_complete_request(ctx, &req);
493 }
494
495 int ubus_send_reply(struct ubus_context *ctx, struct ubus_request_data *req,
496 struct blob_attr *msg)
497 {
498 int ret;
499
500 blob_buf_init(&b, 0);
501 blob_put_int32(&b, UBUS_ATTR_OBJID, req->object);
502 blob_put(&b, UBUS_ATTR_DATA, blob_data(msg), blob_len(msg));
503 ret = ubus_send_msg(ctx, req->seq, b.head, UBUS_MSG_DATA, req->peer);
504 if (ret < 0)
505 return UBUS_STATUS_NO_DATA;
506
507 return 0;
508 }
509
510 void ubus_invoke_async(struct ubus_context *ctx, uint32_t obj, const char *method,
511 struct blob_attr *msg, struct ubus_request *req)
512 {
513 blob_buf_init(&b, 0);
514 blob_put_int32(&b, UBUS_ATTR_OBJID, obj);
515 blob_put_string(&b, UBUS_ATTR_METHOD, method);
516 if (msg)
517 blob_put(&b, UBUS_ATTR_DATA, blob_data(msg), blob_len(msg));
518
519 ubus_start_request(ctx, req, b.head, UBUS_MSG_INVOKE, obj);
520 }
521
522 int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method,
523 struct blob_attr *msg, ubus_data_handler_t cb, void *priv)
524 {
525 struct ubus_request req;
526
527 ubus_invoke_async(ctx, obj, method, msg, &req);
528 req.data_cb = cb;
529 req.priv = priv;
530 return ubus_complete_request(ctx, &req);
531 }
532
533 static void ubus_publish_cb(struct ubus_request *req, int type, struct blob_attr *msg)
534 {
535 struct ubus_object *obj = req->priv;
536
537 ubus_parse_msg(msg);
538
539 if (!attrbuf[UBUS_ATTR_OBJID])
540 return;
541
542 obj->id = blob_get_int32(attrbuf[UBUS_ATTR_OBJID]);
543
544 if (attrbuf[UBUS_ATTR_OBJTYPE])
545 obj->type->id = blob_get_int32(attrbuf[UBUS_ATTR_OBJTYPE]);
546
547 obj->avl.key = &obj->id;
548 avl_insert(&req->ctx->objects, &obj->avl);
549 }
550
551 static bool ubus_push_table_data(const struct ubus_signature **sig, int *rem, bool array)
552 {
553 const struct ubus_signature *cur;
554 bool nest_type;
555 void *nest;
556
557 while (rem) {
558 cur = (*sig)++;
559 (*rem)--;
560 switch(cur->type) {
561 case UBUS_SIGNATURE_END:
562 return !array;
563 case BLOBMSG_TYPE_INT32:
564 case BLOBMSG_TYPE_STRING:
565 blobmsg_add_u32(&b, cur->name, cur->type);
566 break;
567 case BLOBMSG_TYPE_TABLE:
568 case BLOBMSG_TYPE_ARRAY:
569 nest_type = cur->type == BLOBMSG_TYPE_ARRAY;
570 nest = blobmsg_open_nested(&b, cur->name, nest_type);
571 if (!ubus_push_table_data(sig, rem, nest_type))
572 return false;
573 blobmsg_close_table(&b, nest);
574 break;
575 default:
576 return false;
577 }
578 if (array)
579 return true;
580 }
581 return false;
582 }
583
584 static bool ubus_push_object_type(struct ubus_object_type *type)
585 {
586 void *s, *m;
587 int rem = type->n_signature;
588 const struct ubus_signature *sig = type->signature;
589
590 s = blob_nest_start(&b, UBUS_ATTR_SIGNATURE);
591 while (rem) {
592 if (sig->type != UBUS_SIGNATURE_METHOD)
593 return false;
594
595 m = blobmsg_open_table(&b, sig->name);
596
597 sig++;
598 rem--;
599 if (!ubus_push_table_data(&sig, &rem, false))
600 return false;
601
602 blobmsg_close_table(&b, m);
603 }
604 blob_nest_end(&b, s);
605
606 return true;
607 }
608
609 static int __ubus_publish(struct ubus_context *ctx, struct ubus_object *obj)
610 {
611 struct ubus_request req;
612 int ret;
613
614 blob_buf_init(&b, 0);
615
616 if (obj->name && obj->type) {
617 blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->name);
618
619 if (obj->type->id)
620 blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id);
621 else if (!ubus_push_object_type(obj->type))
622 return UBUS_STATUS_INVALID_ARGUMENT;
623 }
624
625 ubus_start_request(ctx, &req, b.head, UBUS_MSG_PUBLISH, 0);
626 req.raw_data_cb = ubus_publish_cb;
627 req.priv = obj;
628 ret = ubus_complete_request(ctx, &req);
629 if (ret)
630 return ret;
631
632 if (!obj->id)
633 return UBUS_STATUS_NO_DATA;
634
635 return 0;
636 }
637
638 int ubus_publish(struct ubus_context *ctx, struct ubus_object *obj)
639 {
640 if (!obj->name || !obj->type)
641 return UBUS_STATUS_INVALID_ARGUMENT;
642
643 return __ubus_publish(ctx, obj);
644 }
645
646 int ubus_register_event_handler(struct ubus_context *ctx, struct ubus_object *obj,
647 const char *pattern)
648 {
649 struct blob_buf b2;
650 int ret;
651
652 if (!obj->id) {
653 if (!!obj->name ^ !!obj->type)
654 return UBUS_STATUS_INVALID_ARGUMENT;
655
656 ret = __ubus_publish(ctx, obj);
657 if (ret)
658 return ret;
659 }
660
661 /* use a second buffer, ubus_invoke() overwrites the primary one */
662 memset(&b2, 0, sizeof(b2));
663 blob_buf_init(&b2, 0);
664 blobmsg_add_u32(&b2, "object", obj->id);
665 if (pattern)
666 blobmsg_add_string(&b2, "pattern", pattern);
667
668 ret = ubus_invoke(ctx, UBUS_SYSTEM_OBJECT_EVENT, "register", b2.head,
669 NULL, NULL);
670
671 return 0;
672 }
673
674
675 void ubus_default_connection_lost(struct ubus_context *ctx)
676 {
677 if (ctx->sock.registered)
678 uloop_end();
679 }
680
681 struct ubus_context *ubus_connect(const char *path)
682 {
683 struct ubus_context *ctx;
684 struct {
685 struct ubus_msghdr hdr;
686 struct blob_attr data;
687 } hdr;
688 struct blob_attr *buf;
689
690 if (!path)
691 path = UBUS_UNIX_SOCKET;
692
693 ctx = calloc(1, sizeof(*ctx));
694 if (!ctx)
695 goto error;
696
697 ctx->sock.fd = usock(USOCK_UNIX, path, NULL);
698 if (ctx->sock.fd < 0)
699 goto error_free;
700
701 ctx->sock.cb = ubus_handle_data;
702
703 if (read(ctx->sock.fd, &hdr, sizeof(hdr)) != sizeof(hdr))
704 goto error_close;
705
706 if (!ubus_validate_hdr(&hdr.hdr))
707 goto error_close;
708
709 if (hdr.hdr.type != UBUS_MSG_HELLO)
710 goto error_close;
711
712 buf = calloc(1, blob_raw_len(&hdr.data));
713 if (!buf)
714 goto error_close;
715
716 memcpy(buf, &hdr.data, sizeof(hdr.data));
717 if (read(ctx->sock.fd, blob_data(buf), blob_len(buf)) != blob_len(buf))
718 goto error_free_buf;
719
720 ctx->local_id = hdr.hdr.peer;
721 free(buf);
722
723 ctx->connection_lost = ubus_default_connection_lost;
724
725 INIT_LIST_HEAD(&ctx->requests);
726 avl_init(&ctx->objects, ubus_cmp_id, false, NULL);
727
728 if (!ctx->local_id)
729 goto error_close;
730
731 return ctx;
732
733 error_free_buf:
734 free(buf);
735 error_close:
736 close(ctx->sock.fd);
737 error_free:
738 free(ctx);
739 error:
740 return NULL;
741 }
742
743 void ubus_free(struct ubus_context *ctx)
744 {
745 close(ctx->sock.fd);
746 free(ctx);
747 }