-
Notifications
You must be signed in to change notification settings - Fork 12
/
libubus-sub.c
133 lines (105 loc) · 3.44 KB
/
libubus-sub.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
* Copyright (C) 2011-2012 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "libubus.h"
#include "libubus-internal.h"
static int ubus_subscriber_cb(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req,
const char *method, struct blob_attr *msg)
{
struct ubus_subscriber *s;
s = container_of(obj, struct ubus_subscriber, obj);
if (s->cb)
return s->cb(ctx, obj, req, method, msg);
return 0;
}
const struct ubus_method watch_method __hidden = {
.name = NULL,
.handler = ubus_subscriber_cb,
};
static void
ubus_auto_sub_event_handler_cb(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *type, struct blob_attr *msg)
{
enum {
EVENT_ID,
EVENT_PATH,
__EVENT_MAX
};
static const struct blobmsg_policy event_policy[__EVENT_MAX] = {
[EVENT_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 },
[EVENT_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
};
struct blob_attr *tb[__EVENT_MAX];
struct ubus_subscriber *s;
const char *path;
int id;
blobmsg_parse(event_policy, __EVENT_MAX, tb, blob_data(msg), blob_len(msg));
if (!tb[EVENT_ID] || !tb[EVENT_PATH])
return;
path = blobmsg_get_string(tb[EVENT_PATH]);
id = blobmsg_get_u32(tb[EVENT_ID]);
list_for_each_entry(s, &ctx->auto_subscribers, list)
if (s->new_obj_cb(ctx, s, path))
ubus_subscribe(ctx, s, id);
}
static void
ubus_auto_sub_lookup(struct ubus_context *ctx, struct ubus_object_data *obj,
void *priv)
{
struct ubus_subscriber *s = priv;
if (s->new_obj_cb(ctx, s, obj->path))
ubus_subscribe(ctx, s, obj->id);
}
int ubus_register_subscriber(struct ubus_context *ctx, struct ubus_subscriber *s)
{
struct ubus_object *obj = &s->obj;
int ret;
if (ubus_context_is_channel(ctx))
return UBUS_STATUS_INVALID_ARGUMENT;
INIT_LIST_HEAD(&s->list);
obj->methods = &watch_method;
obj->n_methods = 1;
ret = ubus_add_object(ctx, obj);
if (ret)
return ret;
if (s->new_obj_cb) {
struct ubus_event_handler *ev = &ctx->auto_subscribe_event_handler;
list_add(&s->list, &ctx->auto_subscribers);
ev->cb = ubus_auto_sub_event_handler_cb;
if (!ev->obj.id)
ubus_register_event_handler(ctx, ev, "ubus.object.add");
ubus_lookup(ctx, NULL, ubus_auto_sub_lookup, s);
}
return 0;
}
static int
__ubus_subscribe_request(struct ubus_context *ctx, struct ubus_object *obj, uint32_t id, int type)
{
struct ubus_request req;
if (ubus_context_is_channel(ctx))
return UBUS_STATUS_INVALID_ARGUMENT;
blob_buf_init(&b, 0);
blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id);
blob_put_int32(&b, UBUS_ATTR_TARGET, id);
if (ubus_start_request(ctx, &req, b.head, type, 0) < 0)
return UBUS_STATUS_INVALID_ARGUMENT;
return ubus_complete_request(ctx, &req, 0);
}
int ubus_subscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id)
{
return __ubus_subscribe_request(ctx, &obj->obj, id, UBUS_MSG_SUBSCRIBE);
}
int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id)
{
return __ubus_subscribe_request(ctx, &obj->obj, id, UBUS_MSG_UNSUBSCRIBE);
}