root/luci2/ubus/libubus.c @ 5855

Revision 5855, 10.9 KB (checked in by blogic, 3 years ago)

typo and double free

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    free(bbuf.buf);
114    list_del(&h->tree);
115    list_del(&h->list);
116    free(h);
117}
118
119static void ubus_hook_call(struct ubus_hook *h, const char *node, int len, void *payload)
120{
121    json_object *j;
122    struct blob_attr *b = 0;
123    const char *n = node;
124    if(!h->cb)
125        return;
126    if(len != h->cnode_len)
127        n = &node[h->cnode_len - 1];
128    switch(h->type)
129    {
130    case HOOK_STRING:
131        ((_ubus_hook_string)h->cb)(n, (payload)?(blob_get_string(payload)):(0));
132        break;
133    case HOOK_JSON:
134        j = json_tokener_parse(blob_get_string(payload));
135        if(!is_error(j))
136            ((_ubus_hook_json)h->cb)(n, j);
137        else
138            printf("%s:%s[%d] incoming json is invalid\n", __FILE__, __func__, __LINE__);
139        break;
140    case HOOK_BLOB:
141        if(payload)
142            b = blob_data(payload);
143        ((_ubus_hook_blob)h->cb)(n, b);
144        break;
145    default:
146        break;
147    }
148}
149
150static struct ubus_hook* ubus_hook_find(const char *node)
151{
152    struct list_head *p;
153    uint32_t hash = sfh_hash(node, strlen(node));
154    list_for_each(p, &hooks)
155    {
156        struct ubus_hook *h = container_of(p, struct ubus_hook, list);
157        if(h->hash == hash)
158            return h;
159    }
160    return 0;
161}
162
163struct ubus_ctx* ubus_ctx_alloc(const char *type, const char *name)
164{
165    struct ubus_ctx *ctx =(struct ubus_ctx*)malloc(sizeof(struct ubus_ctx));
166    memset(ctx, 0, sizeof(struct ubus_ctx));
167    if(name)
168        ctx->name = strdup(name);
169    if(type)
170        ctx->type = strdup(type);
171    if(!type && name)
172        ctx->type = strdup(name);
173    INIT_LIST_HEAD(&tree);
174    INIT_LIST_HEAD(&hooks);
175    return ctx;
176}
177
178void ubus_ctx_free(struct ubus_ctx *ctx)
179{
180    if(!ctx)
181        return;
182    if(ctx->name)
183        free(ctx->name);
184    if(ctx->type)
185        free(ctx->type);
186    if(ctx->s)
187        close(ctx->s);
188    if(bbuf.buf)
189        free(bbuf.buf);
190    if(lbuf.buf)
191        free(lbuf.buf);
192}
193
194static int ubus_send_blob(struct ubus_ctx *ctx, void *buf)
195{
196    int l, k;
197    if(!ctx->s && !buf)
198        return -1;
199    l = blob_pad_len(buf);
200    if(l > 4096)
201    {
202        LOG("message is bigger than 4096\n");
203        return -1;
204    }
205    k = send(ctx->s, buf, l, 0);
206    return k;
207}
208
209static int ubus_recv_blob(struct ubus_ctx *ctx, char *buf, int l)
210{
211    if(!ctx->s && !buf)
212        return -1;
213    return recv(ctx->s, buf, l, 0);
214}
215
216static int ubus_msg_hello(struct ubus_ctx *ctx)
217{
218    char *buf = 0;
219    int l = 0;
220    if(ctx->type)
221        l += strlen(ctx->type);
222    if(ctx->type && ctx->name)
223        l += strlen(ctx->name);
224    if(l)
225    {
226        l += 8;
227        buf = malloc(l);
228        memset(buf, 0, l);
229        *buf = 0;
230        strcat(buf, "hello.");
231        strcat(buf, ctx->type);
232        if(ctx->name)
233        {
234            strcat(buf, ".");
235            strcat(buf, ctx->name);
236        }
237        ubus_msg_encode(UBUS_MSG_CONTROL, buf, 0, 0, 0, 0, &bbuf);
238        free(buf);
239        return ubus_send_blob(ctx, bbuf.buf);
240    }
241    return 0;
242}
243
244static void ubus_reregister_events(struct ubus_ctx *ctx)
245{
246    struct list_head *p;
247    if(list_empty(&hooks))
248        return;
249    list_for_each(p, &hooks)
250    {
251        struct ubus_hook *h = container_of(p, struct ubus_hook, list);
252        ubus_msg_encode(UBUS_MSG_ADD, h->cnode, 0, 0, 0, 0, &bbuf);
253        ubus_send_blob(ctx, bbuf.buf);
254    }
255}
256
257int ubus_connect(struct ubus_ctx *ctx)
258{
259    int s, len;
260    struct sockaddr_un remote;
261    if(ctx->s)
262        return 0;
263
264    if((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
265    {
266        perror("socket");
267        return -1;
268    }
269
270    remote.sun_family = AF_UNIX;
271    strcpy(remote.sun_path, UBUS_SOCK_PATH);
272    len = strlen(remote.sun_path) + sizeof(remote.sun_family);
273
274    if(connect(s, (struct sockaddr *)&remote, len) == -1)
275    {
276        close(s);
277        return -2;
278    }
279    ctx->s = s;
280    LOG("connected to ubus\n");
281    ubus_msg_hello(ctx);
282    ubus_reregister_events(ctx);
283    return ctx->s;
284}
285
286static int ubus_event_dispatch_list(struct list_head *l, const char *node, int len, void *buf)
287{
288    struct list_head *p;
289    list_for_each(p, l)
290    {
291        struct ubus_hook *h = container_of(p, struct ubus_hook, tree);
292        if(h->cb)
293        {
294            ubus_hook_call(h, node, len, buf);
295            return 0;
296        }
297    }
298    return 1;
299}
300
301static void ubus_event_dispatch(const char *cnode, int len, struct blob_attr *node, void *payload)
302{
303    struct blob_attr *pos;
304    int rem;
305    struct list_head *t = &tree;
306    struct ubus_tree *n = 0;
307    struct ubus_hook *h = ubus_hook_find(cnode);
308    if(h)
309    {
310        if(h->cb)
311            ubus_hook_call(h, cnode, len, payload);
312        return;
313    }
314    blob_for_each_attr(pos, node, rem)
315    {
316        if(blob_id(pos) != UBUS_ITEM)
317            return;
318        n = ubus_tree_find_child(t, blob_get_string(pos));
319        if(!n)
320            return;
321        if(!ubus_event_dispatch_list(&n->wildcards, cnode, len, payload))
322            return;
323        t = &n->childs;
324    }
325}
326
327static void ubus_event_incoming(void *buf)
328{
329    struct blob_attr *node, *origin = 0, *payload = 0;
330    int type, flags = 0;
331    const char *cnode;
332    type = ubus_msg_decode(&node, &origin, &payload, &flags, buf);
333    cnode = ubus_to_string(node);
334    switch(type)
335    {
336    case UBUS_MSG_EVENT:
337        ubus_event_dispatch(cnode, strlen(cnode), node, payload);
338        break;
339    default:
340        LOG("unhandled ubus message type\n");
341        break;
342    }
343}
344
345void ubus_recv(struct ubus_ctx *ctx)
346{
347    char reply[4096];
348    char *t = reply;
349    int r;
350    *reply = 0;
351    reply[4095] = 0;
352    r = ubus_recv_blob(ctx, reply, 4095);
353    while(r && (r >= blob_pad_len((void*)t)))
354    {
355        int l = blob_pad_len((void*)t);
356        ubus_event_incoming(t);
357        t += l;
358        r -= l;
359    }
360}
361
362void ubus_poll(struct ubus_ctx *ctx, int timeout)
363{
364    struct pollfd fd;
365    if(!ctx->s)
366        ubus_connect(ctx);
367    if(!ctx->s)
368        return;
369    fd.fd = ctx->s;
370    fd.events = POLLIN | POLLRDHUP;
371    if(poll(&fd, 1, timeout) < 1)
372        return;
373    if(fd.revents & POLLRDHUP)
374    {
375        close(ctx->s);
376        ctx->s = 0;
377        LOG("lost connection to ubus\n");
378    } else if(fd.revents & POLLIN)
379    {
380        ubus_recv(ctx);
381    }
382}
383
384static void _ubus_event_add(struct ubus_ctx *ctx, char *node, int type, _ubus_hook_generic cb)
385{
386    struct blob_attr *n;
387    struct ubus_tree *t;
388    struct ubus_hook *h;
389    int flags;
390    ubus_msg_encode(UBUS_MSG_ADD, node, 0, 0, 0, 0, &bbuf);
391    ubus_msg_decode(&n, 0, 0, &flags, bbuf.buf);
392    t = ubus_tree_find(&tree, n, 1);
393    h = ubus_hook_alloc(n, flags & FLAG_WILDCARD, node, type, cb);
394    if(flags & FLAG_WILDCARD)
395        list_add(&h->tree, &t->wildcards);
396    else
397        list_add(&h->tree, &t->events);
398    ubus_send_blob(ctx, bbuf.buf);
399}
400
401void ubus_event_add(struct ubus_ctx *ctx, char *node, _ubus_hook_string cb)
402{
403    _ubus_event_add(ctx, node, HOOK_STRING, (_ubus_hook_generic)cb);
404}
405
406void ubus_event_add_blob(struct ubus_ctx *ctx, char *node, _ubus_hook_blob cb)
407{
408    _ubus_event_add(ctx, node, HOOK_BLOB, (_ubus_hook_generic)cb);
409}
410
411void ubus_event_add_json(struct ubus_ctx *ctx, char *node, _ubus_hook_json cb)
412{
413    _ubus_event_add(ctx, node, HOOK_JSON, (_ubus_hook_generic)cb);
414}
415
416void ubus_event_del(struct ubus_ctx *ctx, const char *node)
417{
418    struct ubus_hook *h = ubus_hook_find(node);
419    if(!h)
420        return;
421    ubus_msg_encode(UBUS_MSG_DEL, node, 0, 0, 0, 0, &bbuf);
422    ubus_send_blob(ctx, bbuf.buf);
423    usb_hook_free(h);
424}
425
426void ubus_event_send(struct ubus_ctx *ctx, const char *node, const char *payload)
427{
428    if(strstr(node, "*"))
429        return;
430    ubus_msg_encode(UBUS_MSG_EVENT, node, 0, payload, (payload)?(strlen(payload) + 1):(0) , 0, &bbuf);
431    ubus_send_blob(ctx, bbuf.buf);
432}
433
434void ubus_event_send_blob(struct ubus_ctx *ctx, const char *node, void *buf)
435{
436    if(strstr(node, "*"))
437        return;
438    ubus_msg_encode(UBUS_MSG_EVENT, node, 0, buf, blob_pad_len(buf), 0, &bbuf);
439    ubus_send_blob(ctx, bbuf.buf);
440}
441
442void ubus_list_flush(void)
443{
444    blob_buf_init(&lbuf, BLOB_LIST);
445}
446
447void ubus_list_add(const char *key, const char *val)
448{
449    void *nest;
450    if(!key || !val)
451        return;
452    nest = blob_nest_start(&lbuf, LIST_ITEM);
453    blob_put_string(&lbuf, LIST_KEY, key);
454    blob_put_string(&lbuf, LIST_VAL, val);
455    blob_nest_end(&lbuf, nest);
456}
457
458void ubus_event_send_list(struct ubus_ctx *ctx, const char *node)
459{
460    ubus_event_send_blob(ctx, node, lbuf.buf);
461}
462
463const char* ubus_list_get(void *blob, const char *key)
464{
465    struct blob_attr *pos;
466    int rem;
467    if(!blob)
468        return 0;
469    blob_for_each_attr(pos, blob, rem)
470    {
471        struct blob_attr *a;
472        const char *k, *v;
473        if(blob_id(pos) != LIST_ITEM)
474            continue;
475        a = blob_data(pos);
476        if(!a)
477            continue;
478        if(blob_id(a) != LIST_KEY)
479            continue;
480        k = blob_get_string(a);
481        if(strcmp(key, k))
482            continue;
483        a = blob_next(a);
484        if(!a)
485            continue;
486        if(blob_id(a) != LIST_VAL)
487            continue;
488        v = blob_get_string(a);
489        if(!k || !v)
490            continue;
491        return v;
492    }
493    return 0;
494}
495
496void ubus_list_dump(void *blob)
497{
498    struct blob_attr *pos;
499    int rem;
500    if(!blob)
501        return;
502    blob_for_each_attr(pos, blob, rem)
503    {
504        struct blob_attr *a;
505        const char *key, *val;
506        if(blob_id(pos) != LIST_ITEM)
507            continue;
508        a = blob_data(pos);
509        if(!a)
510            continue;
511        if(blob_id(a) != LIST_KEY)
512            continue;
513        key = blob_get_string(a);
514        a = blob_next(a);
515        if(!a)
516            continue;
517        if(blob_id(a) != LIST_VAL)
518            continue;
519        val = blob_get_string(a);
520        if(!key || !val)
521            continue;
522        printf("%s -> %s\n", key, val);
523    }
524}
525
526
Note: See TracBrowser for help on using the browser.