root/luci2/ubus/libubus.c @ 5993

Revision 5993, 11.0 KB (checked in by Cyrus, 3 years ago)

ubus: Fix inconsistency with node name passed to wildcard hooks

Line 
1/*
2 *   ubus - openwrt interconnect
3 *   Copyright (C) 2010 John Crispin <blogic@openwrt.org>
4 *   Copyright (C) 2010 Steven Barth <steven@midlink.org>
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program; if not, write to the Free Software
18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19 *
20 */
21
22#include <unistd.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <errno.h>
26#include <string.h>
27#define __USE_GNU
28#include <poll.h>
29#undef __USE_GNU
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33
34#include <ulog.h>
35#include "libubus.h"
36#include "ubus_tree.h"
37#include "ubus_msg.h"
38#include "ubus_constants.h"
39#include "hash.h"
40
41struct ubus_ctx
42{
43    int s;
44    char *name;
45    char *type;
46};
47
48#define HOOK_STRING         0x01
49#define HOOK_BLOB           0x02
50#define HOOK_JSON           0x04
51typedef void (*_ubus_hook_generic)(char *node, json_object *payload);
52
53struct ubus_hook
54{
55    struct list_head list;
56    struct list_head tree;
57    void *node;
58    char *cnode;
59    int cnode_len;
60    uint32_t hash;
61    int wildcard;
62    int type;
63    _ubus_hook_generic cb;
64};
65
66static struct list_head tree;
67static struct list_head hooks;
68
69static bool buffer_grow(struct blob_buf *buf, int minlen)
70{
71    int l = buf->buflen;
72    buf->buflen += ((minlen / 256) + 1) * 256;
73    buf->buf = realloc(buf->buf, buf->buflen);
74    memset(&((char*)buf->buf)[l], 0, buf->buflen - l);
75    return !!buf->buf;
76}
77
78static struct blob_buf bbuf = {
79    .grow = buffer_grow
80};
81
82static struct blob_buf lbuf = {
83    .grow = buffer_grow
84};
85
86int ubus_get_sock(struct ubus_ctx *ctx)
87{
88    return ctx->s;
89}
90
91static struct ubus_hook* ubus_hook_alloc(void *buf, int wildcard, const char *node, int type, _ubus_hook_generic cb)
92{
93    struct ubus_hook *h = (struct ubus_hook*)malloc(sizeof(struct ubus_hook));
94    int l;
95    memset(h, 0, sizeof(struct ubus_hook));
96    h->wildcard = wildcard;
97    h->cb = cb;
98    l = blob_pad_len(buf);
99    h->node = malloc(l);
100    memcpy(h->node, buf, l);
101    h->hash = sfh_hash(node, strlen(node));
102    h->cnode = strdup(node);
103    h->cnode_len = strlen(node);
104    h->type = type;
105    list_add(&h->list, &hooks);
106    return h;
107}
108
109static void usb_hook_free(struct ubus_hook *h)
110{
111    free(h->node);
112    free(h->cnode);
113    list_del(&h->tree);
114    list_del(&h->list);
115    free(h);
116}
117
118static void ubus_hook_call(struct ubus_hook *h, const char *node, int len, void *payload)
119{
120    json_object *j;
121    struct blob_attr *b = 0;
122    const char *n = node;
123    if(!h->cb)
124        return;
125    if(len != h->cnode_len || h->wildcard)
126        n = &node[h->cnode_len - 1];
127    switch(h->type)
128    {
129    case HOOK_STRING:
130        ((_ubus_hook_string)h->cb)(n, (payload)?(blob_get_string(payload)):(0));
131        break;
132    case HOOK_JSON:
133        j = json_tokener_parse(blob_get_string(payload));
134        if(!is_error(j))
135            ((_ubus_hook_json)h->cb)(n, j);
136        else
137            printf("%s:%s[%d] incoming json is invalid\n", __FILE__, __func__, __LINE__);
138        break;
139    case HOOK_BLOB:
140        if(payload)
141            b = blob_data(payload);
142        ((_ubus_hook_blob)h->cb)(n, b);
143        break;
144    default:
145        break;
146    }
147}
148
149static struct ubus_hook* ubus_hook_find(const char *node)
150{
151    struct list_head *p;
152    uint32_t hash = sfh_hash(node, strlen(node));
153    list_for_each(p, &hooks)
154    {
155        struct ubus_hook *h = container_of(p, struct ubus_hook, list);
156        if(h->hash == hash)
157            return h;
158    }
159    return 0;
160}
161
162struct ubus_ctx* ubus_ctx_alloc(const char *type, const char *name)
163{
164    struct ubus_ctx *ctx =(struct ubus_ctx*)malloc(sizeof(struct ubus_ctx));
165    memset(ctx, 0, sizeof(struct ubus_ctx));
166    if(name)
167        ctx->name = strdup(name);
168    if(type)
169        ctx->type = strdup(type);
170    if(!type && name)
171        ctx->type = strdup(name);
172    INIT_LIST_HEAD(&tree);
173    INIT_LIST_HEAD(&hooks);
174    blob_buf_init(&lbuf, 0);
175    blob_buf_init(&bbuf, 0);
176    return ctx;
177}
178
179void ubus_ctx_free(struct ubus_ctx *ctx)
180{
181    if(!ctx)
182        return;
183    if(ctx->name)
184        free(ctx->name);
185    if(ctx->type)
186        free(ctx->type);
187    if(ctx->s)
188        close(ctx->s);
189    if(bbuf.buf)
190        free(bbuf.buf);
191    if(lbuf.buf)
192        free(lbuf.buf);
193}
194
195static int ubus_send_blob(struct ubus_ctx *ctx, void *buf)
196{
197    int l, k;
198    if(!ctx->s && !buf)
199        return -1;
200    l = blob_pad_len(buf);
201    if(l > 4096)
202    {
203        LOG("message is bigger than 4096\n");
204        return -1;
205    }
206    k = send(ctx->s, buf, l, 0);
207    return k;
208}
209
210static int ubus_recv_blob(struct ubus_ctx *ctx, char *buf, int l)
211{
212    if(!ctx->s && !buf)
213        return -1;
214    return recv(ctx->s, buf, l, 0);
215}
216
217static int ubus_msg_hello(struct ubus_ctx *ctx)
218{
219    char *buf = 0;
220    int l = 0;
221    if(ctx->type)
222        l += strlen(ctx->type);
223    if(ctx->type && ctx->name)
224        l += strlen(ctx->name);
225    if(l)
226    {
227        l += 8;
228        buf = malloc(l);
229        memset(buf, 0, l);
230        *buf = 0;
231        strcat(buf, "hello.");
232        strcat(buf, ctx->type);
233        if(ctx->name)
234        {
235            strcat(buf, ".");
236            strcat(buf, ctx->name);
237        }
238        ubus_msg_encode(UBUS_MSG_CONTROL, buf, 0, 0, 0, 0, &bbuf);
239        free(buf);
240        return ubus_send_blob(ctx, bbuf.buf);
241    }
242    return 0;
243}
244
245static void ubus_reregister_events(struct ubus_ctx *ctx)
246{
247    struct list_head *p;
248    if(list_empty(&hooks))
249        return;
250    list_for_each(p, &hooks)
251    {
252        struct ubus_hook *h = container_of(p, struct ubus_hook, list);
253        ubus_msg_encode(UBUS_MSG_ADD, h->cnode, 0, 0, 0, 0, &bbuf);
254        ubus_send_blob(ctx, bbuf.buf);
255    }
256}
257
258int ubus_connect(struct ubus_ctx *ctx)
259{
260    int s, len;
261    struct sockaddr_un remote;
262    if(ctx->s)
263        return 0;
264
265    if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
266    {
267        perror("socket");
268        return -1;
269    }
270
271    remote.sun_family = AF_UNIX;
272    strcpy(remote.sun_path, UBUS_SOCK_PATH);
273    len = strlen(remote.sun_path) + sizeof(remote.sun_family);
274
275    if(connect(s, (struct sockaddr *)&remote, len) == -1)
276    {
277        close(s);
278        return -2;
279    }
280    ctx->s = s;
281    LOG("connected to ubus\n");
282    ubus_msg_hello(ctx);
283    ubus_reregister_events(ctx);
284    return ctx->s;
285}
286
287static int ubus_event_dispatch_list(struct list_head *l, const char *node, int len, void *buf)
288{
289    struct list_head *p;
290    list_for_each(p, l)
291    {
292        struct ubus_hook *h = container_of(p, struct ubus_hook, tree);
293        if(h->cb)
294        {
295            ubus_hook_call(h, node, len, buf);
296            return 0;
297        }
298    }
299    return 1;
300}
301
302static void ubus_event_dispatch(const char *cnode, int len, struct blob_attr *node, void *payload)
303{
304    struct blob_attr *pos;
305    int rem;
306    struct list_head *t = &tree;
307    struct ubus_tree *n = 0;
308    struct ubus_hook *h = ubus_hook_find(cnode);
309    if(h)
310    {
311        if(h->cb)
312            ubus_hook_call(h, cnode, len, payload);
313        return;
314    }
315    blob_for_each_attr(pos, node, rem)
316    {
317        if(blob_id(pos) != UBUS_ITEM)
318            return;
319        n = ubus_tree_find_child(t, blob_get_string(pos));
320        if(!n)
321            return;
322        if(!ubus_event_dispatch_list(&n->wildcards, cnode, len, payload))
323            return;
324        t = &n->childs;
325    }
326}
327
328static void ubus_event_incoming(void *buf)
329{
330    struct blob_attr *node, *origin = 0, *payload = 0;
331    int type, flags = 0;
332    const char *cnode;
333    type = ubus_msg_decode(&node, &origin, &payload, &flags, buf);
334    cnode = ubus_to_string(node);
335    switch(type)
336    {
337    case UBUS_MSG_EVENT:
338        ubus_event_dispatch(cnode, strlen(cnode), node, payload);
339        break;
340    default:
341        LOG("unhandled ubus message type\n");
342        break;
343    }
344}
345
346void ubus_recv(struct ubus_ctx *ctx)
347{
348    char reply[4096];
349    char *t = reply;
350    int r;
351    *reply = 0;
352    reply[4095] = 0;
353    r = ubus_recv_blob(ctx, reply, 4095);
354    while(r && (r >= blob_pad_len((void*)t)))
355    {
356        int l = blob_pad_len((void*)t);
357        ubus_event_incoming(t);
358        t += l;
359        r -= l;
360    }
361}
362
363void ubus_poll(struct ubus_ctx *ctx, int timeout)
364{
365    struct pollfd fd;
366    if(!ctx->s)
367        ubus_connect(ctx);
368    if(!ctx->s)
369        return;
370    fd.fd = ctx->s;
371    fd.events = POLLIN | POLLRDHUP;
372    if(poll(&fd, 1, timeout) < 1)
373        return;
374    if(fd.revents & POLLRDHUP)
375    {
376        close(ctx->s);
377        ctx->s = 0;
378        LOG("lost connection to ubus\n");
379    } else if(fd.revents & POLLIN)
380    {
381        ubus_recv(ctx);
382    }
383}
384
385static void _ubus_event_add(struct ubus_ctx *ctx, char *node, int type, _ubus_hook_generic cb)
386{
387    struct blob_attr *n;
388    struct ubus_tree *t;
389    struct ubus_hook *h;
390    int flags;
391    ubus_msg_encode(UBUS_MSG_ADD, node, 0, 0, 0, 0, &bbuf);
392    ubus_msg_decode(&n, 0, 0, &flags, bbuf.buf);
393    t = ubus_tree_find(&tree, n, 1);
394    h = ubus_hook_alloc(n, flags & FLAG_WILDCARD, node, type, cb);
395    if(flags & FLAG_WILDCARD)
396        list_add(&h->tree, &t->wildcards);
397    else
398        list_add(&h->tree, &t->events);
399    ubus_send_blob(ctx, bbuf.buf);
400}
401
402void ubus_event_add(struct ubus_ctx *ctx, char *node, _ubus_hook_string cb)
403{
404    _ubus_event_add(ctx, node, HOOK_STRING, (_ubus_hook_generic)cb);
405}
406
407void ubus_event_add_blob(struct ubus_ctx *ctx, char *node, _ubus_hook_blob cb)
408{
409    _ubus_event_add(ctx, node, HOOK_BLOB, (_ubus_hook_generic)cb);
410}
411
412void ubus_event_add_json(struct ubus_ctx *ctx, char *node, _ubus_hook_json cb)
413{
414    _ubus_event_add(ctx, node, HOOK_JSON, (_ubus_hook_generic)cb);
415}
416
417void ubus_event_del(struct ubus_ctx *ctx, const char *node)
418{
419    struct ubus_hook *h = ubus_hook_find(node);
420    if(!h)
421        return;
422    ubus_msg_encode(UBUS_MSG_DEL, node, 0, 0, 0, 0, &bbuf);
423    ubus_send_blob(ctx, bbuf.buf);
424    usb_hook_free(h);
425}
426
427void ubus_event_send(struct ubus_ctx *ctx, const char *node, const char *payload)
428{
429    if(strstr(node, "*"))
430        return;
431    ubus_msg_encode(UBUS_MSG_EVENT, node, 0, payload, (payload)?(strlen(payload) + 1):(0) , 0, &bbuf);
432    ubus_send_blob(ctx, bbuf.buf);
433}
434
435void ubus_event_send_blob(struct ubus_ctx *ctx, const char *node, void *buf)
436{
437    if(strstr(node, "*"))
438        return;
439    ubus_msg_encode(UBUS_MSG_EVENT, node, 0, buf, blob_pad_len(buf), 0, &bbuf);
440    ubus_send_blob(ctx, bbuf.buf);
441}
442
443void ubus_list_flush(void)
444{
445    blob_buf_init(&lbuf, BLOB_LIST);
446}
447
448void ubus_list_add(const char *key, const char *val)
449{
450    void *nest;
451    if(!key || !val)
452        return;
453    nest = blob_nest_start(&lbuf, LIST_ITEM);
454    blob_put_string(&lbuf, LIST_KEY, key);
455    blob_put_string(&lbuf, LIST_VAL, val);
456    blob_nest_end(&lbuf, nest);
457}
458
459void ubus_event_send_list(struct ubus_ctx *ctx, const char *node)
460{
461    ubus_event_send_blob(ctx, node, lbuf.buf);
462}
463
464const char* ubus_list_get(void *blob, const char *key)
465{
466    struct blob_attr *pos;
467    int rem;
468    if(!blob)
469        return 0;
470    blob_for_each_attr(pos, blob, rem)
471    {
472        struct blob_attr *a;
473        const char *k, *v;
474        if(blob_id(pos) != LIST_ITEM)
475            continue;
476        a = blob_data(pos);
477        if(!a)
478            continue;
479        if(blob_id(a) != LIST_KEY)
480            continue;
481        k = blob_get_string(a);
482        if(strcmp(key, k))
483            continue;
484        a = blob_next(a);
485        if(!a)
486            continue;
487        if(blob_id(a) != LIST_VAL)
488            continue;
489        v = blob_get_string(a);
490        if(!k || !v)
491            continue;
492        return v;
493    }
494    return 0;
495}
496
497void ubus_list_dump(void *blob)
498{
499    struct blob_attr *pos;
500    int rem;
501    if(!blob)
502        return;
503    blob_for_each_attr(pos, blob, rem)
504    {
505        struct blob_attr *a;
506        const char *key, *val;
507        if(blob_id(pos) != LIST_ITEM)
508            continue;
509        a = blob_data(pos);
510        if(!a)
511            continue;
512        if(blob_id(a) != LIST_KEY)
513            continue;
514        key = blob_get_string(a);
515        a = blob_next(a);
516        if(!a)
517            continue;
518        if(blob_id(a) != LIST_VAL)
519            continue;
520        val = blob_get_string(a);
521        if(!key || !val)
522            continue;
523        printf("%s -> %s\n", key, val);
524    }
525}
526
527
Note: See TracBrowser for help on using the browser.