2 * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <arpa/inet.h>
17 static struct avl_tree patterns
;
18 static struct ubus_object
*event_obj
;
19 static int event_seq
= 0;
20 static int obj_event_seq
= 1;
23 struct list_head list
;
24 struct ubus_object
*obj
;
29 static void ubusd_delete_event_source(struct event_source
*evs
)
32 avl_delete(&patterns
, &evs
->avl
);
36 void ubusd_event_cleanup_object(struct ubus_object
*obj
)
38 struct event_source
*ev
, *tmp
;
40 list_for_each_entry_safe(ev
, tmp
, &obj
->events
, list
) {
41 ubusd_delete_event_source(ev
);
51 static struct blobmsg_policy evr_policy
[] = {
52 [EVREG_PATTERN
] = { .name
= "pattern", .type
= BLOBMSG_TYPE_STRING
},
53 [EVREG_OBJECT
] = { .name
= "object", .type
= BLOBMSG_TYPE_INT32
},
56 static int ubusd_alloc_event_pattern(struct ubus_client
*cl
, struct blob_attr
*msg
)
58 struct event_source
*ev
;
59 struct ubus_object
*obj
;
60 struct blob_attr
*attr
[EVREG_LAST
];
67 return UBUS_STATUS_INVALID_ARGUMENT
;
69 blobmsg_parse(evr_policy
, EVREG_LAST
, attr
, blob_data(msg
), blob_len(msg
));
70 if (!attr
[EVREG_OBJECT
] || !attr
[EVREG_PATTERN
])
71 return UBUS_STATUS_INVALID_ARGUMENT
;
73 id
= blobmsg_get_u32(attr
[EVREG_OBJECT
]);
74 if (id
< UBUS_SYSTEM_OBJECT_MAX
)
75 return UBUS_STATUS_PERMISSION_DENIED
;
77 obj
= ubusd_find_object(id
);
79 return UBUS_STATUS_NOT_FOUND
;
81 if (obj
->client
!= cl
)
82 return UBUS_STATUS_PERMISSION_DENIED
;
84 pattern
= blobmsg_data(attr
[EVREG_PATTERN
]);
86 len
= strlen(pattern
);
87 if (pattern
[len
- 1] == '*') {
93 if (pattern
[0] && ubusd_acl_check(cl
, pattern
, NULL
, UBUS_ACL_LISTEN
))
94 return UBUS_STATUS_PERMISSION_DENIED
;
96 ev
= calloc(1, sizeof(*ev
) + len
+ 1);
98 return UBUS_STATUS_NO_DATA
;
100 list_add(&ev
->list
, &obj
->events
);
102 ev
->partial
= partial
;
103 name
= (char *) (ev
+ 1);
104 strcpy(name
, pattern
);
106 avl_insert(&patterns
, &ev
->avl
);
111 static void ubusd_send_event_msg(struct ubus_msg_buf
**ub
, struct ubus_client
*cl
,
112 struct ubus_object
*obj
, const char *id
,
113 event_fill_cb fill_cb
, void *cb_priv
)
117 /* do not loop back events */
118 if (obj
->client
== cl
)
121 /* do not send duplicate events */
122 if (obj
->event_seen
== obj_event_seq
)
125 obj
->event_seen
= obj_event_seq
;
128 *ub
= fill_cb(cb_priv
, id
);
129 (*ub
)->hdr
.type
= UBUS_MSG_INVOKE
;
133 objid_ptr
= blob_data(blob_data((*ub
)->data
));
134 *objid_ptr
= htonl(obj
->id
.id
);
136 (*ub
)->hdr
.seq
= ++event_seq
;
137 ubus_msg_send(obj
->client
, *ub
);
140 int ubusd_send_event(struct ubus_client
*cl
, const char *id
,
141 event_fill_cb fill_cb
, void *cb_priv
)
143 struct ubus_msg_buf
*ub
= NULL
;
144 struct event_source
*ev
;
147 if (ubusd_acl_check(cl
, id
, NULL
, UBUS_ACL_SEND
))
148 return UBUS_STATUS_PERMISSION_DENIED
;
153 * Since this tree is sorted alphabetically, we can only expect to find
154 * matching entries as long as the number of matching characters
155 * between the pattern string and our string is monotonically increasing.
157 avl_for_each_element(&patterns
, ev
, avl
) {
158 const char *key
= ev
->avl
.key
;
162 full_match
= ubus_strmatch_len(id
, key
, &cur_match_len
);
163 if (cur_match_len
< match_len
)
166 match_len
= cur_match_len
;
172 if (match_len
!= (int) strlen(key
))
176 ubusd_send_event_msg(&ub
, cl
, ev
->obj
, id
, fill_cb
, cb_priv
);
191 static struct blobmsg_policy ev_policy
[] = {
192 [EVMSG_ID
] = { .name
= "id", .type
= BLOBMSG_TYPE_STRING
},
193 [EVMSG_DATA
] = { .name
= "data", .type
= BLOBMSG_TYPE_TABLE
},
196 static struct ubus_msg_buf
*
197 ubusd_create_event_from_msg(void *priv
, const char *id
)
199 struct blob_attr
*msg
= priv
;
201 blob_buf_init(&b
, 0);
202 blob_put_int32(&b
, UBUS_ATTR_OBJID
, 0);
203 blob_put_string(&b
, UBUS_ATTR_METHOD
, id
);
204 blob_put(&b
, UBUS_ATTR_DATA
, blobmsg_data(msg
), blobmsg_data_len(msg
));
206 return ubus_msg_new(b
.head
, blob_raw_len(b
.head
), true);
209 static int ubusd_forward_event(struct ubus_client
*cl
, struct blob_attr
*msg
)
211 struct blob_attr
*data
;
212 struct blob_attr
*attr
[EVMSG_LAST
];
216 return UBUS_STATUS_INVALID_ARGUMENT
;
218 blobmsg_parse(ev_policy
, EVMSG_LAST
, attr
, blob_data(msg
), blob_len(msg
));
219 if (!attr
[EVMSG_ID
] || !attr
[EVMSG_DATA
])
220 return UBUS_STATUS_INVALID_ARGUMENT
;
222 id
= blobmsg_data(attr
[EVMSG_ID
]);
223 data
= attr
[EVMSG_DATA
];
225 if (!strncmp(id
, "ubus.", 5))
226 return UBUS_STATUS_PERMISSION_DENIED
;
228 return ubusd_send_event(cl
, id
, ubusd_create_event_from_msg
, data
);
231 static int ubusd_event_recv(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
, const char *method
, struct blob_attr
*msg
)
233 if (!strcmp(method
, "register"))
234 return ubusd_alloc_event_pattern(cl
, msg
);
236 if (!strcmp(method
, "send"))
237 return ubusd_forward_event(cl
, msg
);
239 return UBUS_STATUS_INVALID_COMMAND
;
242 static struct ubus_msg_buf
*
243 ubusd_create_object_event_msg(void *priv
, const char *id
)
245 struct ubus_object
*obj
= priv
;
248 blob_buf_init(&b
, 0);
249 blob_put_int32(&b
, UBUS_ATTR_OBJID
, 0);
250 blob_put_string(&b
, UBUS_ATTR_METHOD
, id
);
251 s
= blob_nest_start(&b
, UBUS_ATTR_DATA
);
252 blobmsg_add_u32(&b
, "id", obj
->id
.id
);
253 blobmsg_add_string(&b
, "path", obj
->path
.key
);
254 blob_nest_end(&b
, s
);
256 return ubus_msg_new(b
.head
, blob_raw_len(b
.head
), true);
259 void ubusd_send_obj_event(struct ubus_object
*obj
, bool add
)
261 const char *id
= add
? "ubus.object.add" : "ubus.object.remove";
263 ubusd_send_event(NULL
, id
, ubusd_create_object_event_msg
, obj
);
266 void ubusd_event_init(void)
268 ubus_init_string_tree(&patterns
, true);
269 event_obj
= ubusd_create_object_internal(NULL
, UBUS_SYSTEM_OBJECT_EVENT
);
270 if (event_obj
!= NULL
)
271 event_obj
->recv_msg
= ubusd_event_recv
;