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