e770ce398eea12e80cc4108789d49f984e17f8cb
[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_NOT_FOUND] = "Not found",
28         [UBUS_STATUS_NO_DATA] = "No response",
29 };
30
31 static struct blob_buf b;
32
33 static const struct blob_attr_info ubus_policy[UBUS_ATTR_MAX] = {
34         [UBUS_ATTR_STATUS] = { .type = BLOB_ATTR_INT32 },
35         [UBUS_ATTR_OBJID] = { .type = BLOB_ATTR_INT32 },
36         [UBUS_ATTR_OBJPATH] = { .type = BLOB_ATTR_STRING },
37 };
38 static struct blob_attr *attrbuf[UBUS_ATTR_MAX];
39
40 struct ubus_pending_data {
41         struct list_head list;
42         int type;
43         struct blob_attr data[];
44 };
45
46 static int ubus_cmp_id(const void *k1, const void *k2, void *ptr)
47 {
48         const uint32_t *id1 = k1, *id2 = k2;
49
50         if (*id1 < *id2)
51                 return -1;
52         else
53                 return *id1 > *id2;
54 }
55
56 struct blob_attr **ubus_parse_msg(struct blob_attr *msg)
57 {
58         blob_parse(msg, attrbuf, ubus_policy, UBUS_ATTR_MAX);
59         return attrbuf;
60 }
61
62 const char *ubus_strerror(int error)
63 {
64         static char err[32];
65
66         if (error < 0 || error >= __UBUS_STATUS_LAST)
67                 goto out;
68
69         if (!__ubus_strerror[error])
70                 goto out;
71
72         return __ubus_strerror[error];
73
74 out:
75         sprintf(err, "Unknown error: %d", error);
76         return err;
77 }
78
79 static int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
80                          struct blob_attr *msg, int cmd, uint32_t peer)
81 {
82         struct ubus_msghdr hdr;
83         struct iovec iov[2] = {
84                 STATIC_IOV(hdr)
85         };
86
87         hdr.version = 0;
88         hdr.type = cmd;
89         hdr.seq = seq;
90         hdr.peer = peer;
91
92         if (!msg) {
93                 blob_buf_init(&b, 0);
94                 msg = b.head;
95         }
96
97         iov[1].iov_base = (char *) msg;
98         iov[1].iov_len = blob_raw_len(msg);
99
100         return writev(ctx->sock.fd, iov, 2);
101 }
102
103 int ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
104                        struct blob_attr *msg, int cmd, uint32_t peer)
105 {
106         memset(req, 0, sizeof(*req));
107
108         INIT_LIST_HEAD(&req->list);
109         INIT_LIST_HEAD(&req->pending);
110         req->ctx = ctx;
111         req->peer = peer;
112         req->seq = ++ctx->request_seq;
113         return ubus_send_msg(ctx, req->seq, msg, cmd, peer);
114 }
115
116 static bool recv_retry(int fd, struct iovec *iov, bool wait)
117 {
118         int bytes;
119
120         while (iov->iov_len > 0) {
121                 bytes = read(fd, iov->iov_base, iov->iov_len);
122                 if (bytes < 0) {
123                         bytes = 0;
124                         if (errno == EINTR)
125                                 continue;
126
127                         if (errno != EAGAIN) {
128                                 perror("read");
129                                 return false;
130                         }
131                 }
132                 if (!wait && !bytes)
133                         return false;
134
135                 wait = true;
136                 iov->iov_len -= bytes;
137                 iov->iov_base += bytes;
138         }
139
140         return true;
141 }
142
143 static bool ubus_validate_hdr(struct ubus_msghdr *hdr)
144 {
145         if (hdr->version != 0)
146                 return false;
147
148         if (blob_raw_len(hdr->data) < sizeof(*hdr->data))
149                 return false;
150
151         if (blob_raw_len(hdr->data) + sizeof(*hdr) > UBUS_MAX_MSGLEN)
152                 return false;
153
154         return true;
155 }
156
157 static bool get_next_msg(struct ubus_context *ctx, bool wait)
158 {
159         struct iovec iov = STATIC_IOV(ctx->msgbuf.hdr);
160
161         /* receive header + start attribute */
162         iov.iov_len += sizeof(struct blob_attr);
163         if (!recv_retry(ctx->sock.fd, &iov, wait))
164                 return false;
165
166         iov.iov_len = blob_len(ctx->msgbuf.hdr.data);
167         if (iov.iov_len > 0 && !recv_retry(ctx->sock.fd, &iov, true))
168                 return false;
169
170         return ubus_validate_hdr(&ctx->msgbuf.hdr);
171 }
172
173 static bool ubus_get_status(struct ubus_msghdr *hdr, int *ret)
174 {
175         ubus_parse_msg(hdr->data);
176
177         if (!attrbuf[UBUS_ATTR_STATUS])
178                 return false;
179
180         *ret = blob_get_int32(attrbuf[UBUS_ATTR_STATUS]);
181         return true;
182 }
183
184 static void ubus_process_req_data(struct ubus_request *req)
185 {
186         struct ubus_pending_data *data;
187
188         while (!list_empty(&req->pending)) {
189                 data = list_first_entry(&req->pending,
190                         struct ubus_pending_data, list);
191                 list_del(&data->list);
192                 if (!req->cancelled)
193                         req->data_cb(req, data->type, data->data);
194                 free(data);
195         }
196 }
197
198 static void ubus_req_complete_cb(struct ubus_request *req)
199 {
200         ubus_complete_handler_t cb = req->complete_cb;
201
202         if (!cb)
203                 return;
204
205         req->complete_cb = NULL;
206         cb(req, req->status_code);
207 }
208
209 static int ubus_process_req_status(struct ubus_request *req, struct ubus_msghdr *hdr)
210 {
211         int ret = UBUS_STATUS_INVALID_ARGUMENT;
212
213         if (!list_empty(&req->list))
214                 list_del(&req->list);
215
216         ubus_get_status(hdr, &ret);
217         req->peer = hdr->peer;
218         req->status_msg = true;
219         req->status_code = ret;
220         if (!req->blocked)
221                 ubus_req_complete_cb(req);
222
223         return ret;
224 }
225
226 static void ubus_req_data(struct ubus_request *req, struct ubus_msghdr *hdr)
227 {
228         struct ubus_pending_data *data;
229         int len;
230
231         if (!req->blocked) {
232                 req->blocked = true;
233                 req->data_cb(req, hdr->type, hdr->data);
234                 ubus_process_req_data(req);
235                 req->blocked = false;
236
237                 if (req->status_msg)
238                         ubus_req_complete_cb(req);
239
240                 return;
241         }
242
243         len = blob_raw_len(hdr->data);
244         data = calloc(1, sizeof(*data) + len);
245         if (!data)
246                 return;
247
248         data->type = hdr->type;
249         memcpy(data->data, hdr->data, len);
250         list_add(&data->list, &req->pending);
251 }
252
253 static struct ubus_request *ubus_find_request(struct ubus_context *ctx, uint32_t seq, uint32_t peer)
254 {
255         struct ubus_request *req;
256
257         list_for_each_entry(req, &ctx->requests, list) {
258                 if (seq != req->seq || peer != req->peer)
259                         continue;
260
261                 return req;
262         }
263         return NULL;
264 }
265
266 static void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr)
267 {
268         uint32_t objid = 0;
269         int ret = 0;
270
271         ubus_parse_msg(hdr->data);
272
273         if (attrbuf[UBUS_ATTR_OBJID])
274                 objid = blob_get_int32(attrbuf[UBUS_ATTR_OBJID]);
275
276         blob_buf_init(&b, 0);
277         blob_put_int32(&b, UBUS_ATTR_STATUS, ret);
278         blob_put_int32(&b, UBUS_ATTR_OBJID, objid);
279         ubus_send_msg(ctx, hdr->seq, b.head, UBUS_MSG_STATUS, hdr->peer);
280 }
281
282 static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
283 {
284         struct ubus_request *req;
285
286         switch(hdr->type) {
287         case UBUS_MSG_STATUS:
288                 req = ubus_find_request(ctx, hdr->seq, hdr->peer);
289                 if (!req)
290                         break;
291
292                 ubus_process_req_status(req, hdr);
293                 break;
294
295         case UBUS_MSG_DATA:
296                 req = ubus_find_request(ctx, hdr->seq, hdr->peer);
297                 if (req && req->data_cb)
298                         ubus_req_data(req, hdr);
299                 break;
300
301         case UBUS_MSG_INVOKE:
302                 ubus_process_invoke(ctx, hdr);
303                 break;
304         default:
305                 DPRINTF("unknown message type: %d\n", hdr->type);
306                 break;
307         }
308 }
309
310 void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req)
311 {
312         if (!list_empty(&req->list))
313                 return;
314
315         req->cancelled = true;
316         ubus_process_req_data(req);
317         list_del(&req->list);
318 }
319
320 void ubus_complete_request_async(struct ubus_context *ctx, struct ubus_request *req)
321 {
322         if (!list_empty(&req->list))
323                 return;
324
325         list_add(&req->list, &ctx->requests);
326 }
327
328 static void ubus_handle_data(struct uloop_fd *u, unsigned int events)
329 {
330         struct ubus_context *ctx = container_of(u, struct ubus_context, sock);
331         struct ubus_msghdr *hdr = &ctx->msgbuf.hdr;
332
333         while (get_next_msg(ctx, false))
334                 ubus_process_msg(ctx, hdr);
335 }
336
337 int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req)
338 {
339         struct ubus_msghdr *hdr = &ctx->msgbuf.hdr;
340
341         if (!list_empty(&req->list))
342                 list_del(&req->list);
343
344         while (1) {
345                 if (req->status_msg)
346                         return req->status_code;
347
348                 if (req->cancelled)
349                         return UBUS_STATUS_NO_DATA;
350
351                 if (!get_next_msg(ctx, true))
352                         return UBUS_STATUS_NO_DATA;
353
354                 if (hdr->seq != req->seq || hdr->peer != req->peer)
355                         goto skip;
356
357                 switch(hdr->type) {
358                 case UBUS_MSG_STATUS:
359                         return ubus_process_req_status(req, hdr);
360                 case UBUS_MSG_DATA:
361                         if (req->data_cb)
362                                 ubus_req_data(req, hdr);
363                         continue;
364                 default:
365                         goto skip;
366                 }
367
368 skip:
369                 ubus_process_msg(ctx, hdr);
370         }
371 }
372
373 void ubus_invoke_async(struct ubus_context *ctx, uint32_t obj, const char *method,
374                        struct blob_attr *msg, struct ubus_request *req)
375 {
376         blob_buf_init(&b, 0);
377         blob_put_int32(&b, UBUS_ATTR_OBJID, obj);
378         blob_put_string(&b, UBUS_ATTR_METHOD, method);
379         blob_put(&b, UBUS_ATTR_DATA, blob_data(msg), blob_len(msg));
380
381         ubus_start_request(ctx, req, b.head, UBUS_MSG_INVOKE, obj);
382 }
383
384 int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method,
385                 struct blob_attr *msg, ubus_data_handler_t cb, void *priv)
386 {
387         struct ubus_request req;
388
389         ubus_invoke_async(ctx, obj, method, msg, &req);
390         req.data_cb = cb;
391         req.priv = priv;
392         return ubus_complete_request(ctx, &req);
393 }
394
395 static void ubus_publish_cb(struct ubus_request *req, int type, struct blob_attr *msg)
396 {
397         struct ubus_object *obj = req->priv;
398
399         ubus_parse_msg(msg);
400
401         if (!attrbuf[UBUS_ATTR_OBJID])
402                 return;
403
404         obj->id = blob_get_int32(attrbuf[UBUS_ATTR_OBJID]);
405
406         if (attrbuf[UBUS_ATTR_OBJTYPE])
407                 obj->type->id = blob_get_int32(attrbuf[UBUS_ATTR_OBJTYPE]);
408
409         obj->avl.key = &obj->id;
410         avl_insert(&req->ctx->objects, &obj->avl);
411 }
412
413 static bool ubus_push_table_data(const struct ubus_signature **sig, int *rem, bool array)
414 {
415         const struct ubus_signature *cur;
416         bool nest_type;
417         void *nest;
418
419         while (rem) {
420                 cur = (*sig)++;
421                 (*rem)--;
422                 switch(cur->type) {
423                 case UBUS_SIGNATURE_END:
424                         return !array;
425                 case BLOBMSG_TYPE_INT32:
426                 case BLOBMSG_TYPE_STRING:
427                         blobmsg_add_u32(&b, cur->name, cur->type);
428                         break;
429                 case BLOBMSG_TYPE_TABLE:
430                 case BLOBMSG_TYPE_ARRAY:
431                         nest_type = cur->type == BLOBMSG_TYPE_ARRAY;
432                         nest = blobmsg_open_nested(&b, cur->name, nest_type);
433                         if (!ubus_push_table_data(sig, rem, nest_type))
434                                 return false;
435                         blobmsg_close_table(&b, nest);
436                         break;
437                 default:
438                         return false;
439                 }
440                 if (array)
441                         return true;
442         }
443         return false;
444 }
445
446 static bool ubus_push_object_type(struct ubus_object_type *type)
447 {
448         void *s, *m;
449         int rem = type->n_signature;
450         const struct ubus_signature *sig = type->signature;
451
452         s = blob_nest_start(&b, UBUS_ATTR_SIGNATURE);
453         while (rem) {
454                 if (sig->type != UBUS_SIGNATURE_METHOD)
455                         return false;
456
457                 m = blobmsg_open_table(&b, sig->name);
458
459                 sig++;
460                 rem--;
461                 if (!ubus_push_table_data(&sig, &rem, false))
462                         return false;
463
464                 blobmsg_close_table(&b, m);
465         }
466         blob_nest_end(&b, s);
467
468         return true;
469 }
470
471 int ubus_publish(struct ubus_context *ctx, struct ubus_object *obj)
472 {
473         struct ubus_request req;
474         int ret;
475
476         if (obj->id || !obj->name || !obj->type)
477                 return UBUS_STATUS_INVALID_ARGUMENT;
478
479         blob_buf_init(&b, 0);
480         blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->name);
481
482         if (obj->type->id)
483                 blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id);
484         else if (!ubus_push_object_type(obj->type))
485                 return UBUS_STATUS_INVALID_ARGUMENT;
486
487         ubus_start_request(ctx, &req, b.head, UBUS_MSG_PUBLISH, 0);
488         req.data_cb = ubus_publish_cb;
489         req.priv = obj;
490         ret = ubus_complete_request(ctx, &req);
491         if (ret)
492                 return ret;
493
494         if (!obj->id)
495                 return UBUS_STATUS_NO_DATA;
496
497         return 0;
498 }
499
500 struct ubus_context *ubus_connect(const char *path)
501 {
502         struct ubus_context *ctx;
503         struct {
504                 struct ubus_msghdr hdr;
505                 struct blob_attr data;
506         } hdr;
507         struct blob_attr *buf;
508
509         if (!path)
510                 path = UBUS_UNIX_SOCKET;
511
512         ctx = calloc(1, sizeof(*ctx));
513         if (!ctx)
514                 goto error;
515
516         ctx->sock.fd = usock(USOCK_UNIX, path, NULL);
517         if (ctx->sock.fd < 0) {
518                 DPRINTF("Failed to connect to server\n");
519                 goto error_free;
520         }
521         ctx->sock.cb = ubus_handle_data;
522
523         if (read(ctx->sock.fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
524                 DPRINTF("Failed to read initial message data\n");
525                 goto error_close;
526         }
527
528         if (!ubus_validate_hdr(&hdr.hdr)) {
529                 DPRINTF("Failed to validate initial message header\n");
530                 goto error_close;
531         }
532
533         if (hdr.hdr.type != UBUS_MSG_HELLO) {
534                 DPRINTF("Unexpected initial message\n");
535                 goto error_close;
536         }
537
538         buf = calloc(1, blob_raw_len(&hdr.data));
539         if (!buf)
540                 goto error_close;
541
542         memcpy(buf, &hdr.data, sizeof(hdr.data));
543         if (read(ctx->sock.fd, blob_data(buf), blob_len(buf)) != blob_len(buf)) {
544                 DPRINTF("Failed to retrieve initial message data\n");
545                 goto error_free_buf;
546         }
547
548         ctx->local_id = hdr.hdr.peer;
549         free(buf);
550
551         INIT_LIST_HEAD(&ctx->requests);
552         avl_init(&ctx->objects, ubus_cmp_id, false, NULL);
553
554         if (!ctx->local_id) {
555                 DPRINTF("Failed to get local peer id\n");
556                 goto error_close;
557         }
558
559         return ctx;
560
561 error_free_buf:
562         free(buf);
563 error_close:
564         close(ctx->sock.fd);
565 error_free:
566         free(ctx);
567 error:
568         return NULL;
569 }
570
571 void ubus_free(struct ubus_context *ctx)
572 {
573         close(ctx->sock.fd);
574         free(ctx);
575 }