1 /* 2 * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org> 3 * 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 7 * 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. 12 */ 13 14 #include <arpa/inet.h> 15 #include "ubusd.h" 16 17 static struct avl_tree patterns; 18 static struct ubus_object *event_obj; 19 static uint16_t event_seq = 0; 20 static int obj_event_seq = 1; 21 22 struct event_source { 23 struct list_head list; 24 struct ubus_object *obj; 25 struct avl_node avl; 26 bool partial; 27 }; 28 29 static void ubusd_delete_event_source(struct event_source *evs) 30 { 31 list_del(&evs->list); 32 avl_delete(&patterns, &evs->avl); 33 free(evs); 34 } 35 36 void ubusd_event_cleanup_object(struct ubus_object *obj) 37 { 38 struct event_source *ev, *tmp; 39 40 list_for_each_entry_safe(ev, tmp, &obj->events, list) { 41 ubusd_delete_event_source(ev); 42 } 43 } 44 45 enum { 46 EVREG_PATTERN, 47 EVREG_OBJECT, 48 EVREG_LAST, 49 }; 50 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 }, 54 }; 55 56 static int ubusd_alloc_event_pattern(struct ubus_client *cl, struct blob_attr *msg) 57 { 58 struct event_source *ev; 59 struct ubus_object *obj; 60 struct blob_attr *attr[EVREG_LAST]; 61 char *pattern, *name; 62 uint32_t id; 63 bool partial = false; 64 size_t len; 65 66 if (!msg) 67 return UBUS_STATUS_INVALID_ARGUMENT; 68 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; 72 73 id = blobmsg_get_u32(attr[EVREG_OBJECT]); 74 if (id < UBUS_SYSTEM_OBJECT_MAX) 75 return UBUS_STATUS_PERMISSION_DENIED; 76 77 obj = ubusd_find_object(id); 78 if (!obj) 79 return UBUS_STATUS_NOT_FOUND; 80 81 if (obj->client != cl) 82 return UBUS_STATUS_PERMISSION_DENIED; 83 84 pattern = blobmsg_data(attr[EVREG_PATTERN]); 85 86 len = strlen(pattern); 87 if (!len) 88 return UBUS_STATUS_PERMISSION_DENIED; 89 90 if (pattern[len - 1] == '*') { 91 partial = true; 92 pattern[len - 1] = 0; 93 len--; 94 } 95 96 if (ubusd_acl_check(cl, pattern, NULL, UBUS_ACL_LISTEN)) 97 return UBUS_STATUS_PERMISSION_DENIED; 98 99 ev = calloc(1, sizeof(*ev) + len + 1); 100 if (!ev) 101 return UBUS_STATUS_NO_DATA; 102 103 list_add(&ev->list, &obj->events); 104 ev->obj = obj; 105 ev->partial = partial; 106 name = (char *) (ev + 1); 107 strcpy(name, pattern); 108 ev->avl.key = name; 109 avl_insert(&patterns, &ev->avl); 110 111 return 0; 112 } 113 114 static int ubusd_send_event_msg(struct ubus_msg_buf **ub, struct ubus_client *cl, 115 struct ubus_object *obj, const char *id, 116 event_fill_cb fill_cb, void *cb_priv) 117 { 118 uint32_t *objid_ptr; 119 120 /* do not loop back events */ 121 if (obj->client == cl) 122 return 0; 123 124 /* do not send duplicate events */ 125 if (obj->event_seen == obj_event_seq) 126 return 0; 127 128 obj->event_seen = obj_event_seq; 129 130 if (!*ub) { 131 *ub = fill_cb(cb_priv, id); 132 if (!*ub) 133 return UBUS_STATUS_UNKNOWN_ERROR; 134 (*ub)->hdr.type = UBUS_MSG_INVOKE; 135 (*ub)->hdr.peer = 0; 136 } 137 138 objid_ptr = blob_data(blob_data((*ub)->data)); 139 *objid_ptr = htonl(obj->id.id); 140 141 (*ub)->hdr.seq = ++event_seq; 142 ubus_msg_send(obj->client, *ub); 143 return 0; 144 } 145 146 int ubusd_send_event(struct ubus_client *cl, const char *id, 147 event_fill_cb fill_cb, void *cb_priv) 148 { 149 struct ubus_msg_buf *ub = NULL; 150 struct event_source *ev; 151 int match_len = 0; 152 int ret = 0; 153 154 if (ubusd_acl_check(cl, id, NULL, UBUS_ACL_SEND)) 155 return UBUS_STATUS_PERMISSION_DENIED; 156 157 obj_event_seq++; 158 159 /* 160 * Since this tree is sorted alphabetically, we can only expect to find 161 * matching entries as long as the number of matching characters 162 * between the pattern string and our string is monotonically increasing. 163 */ 164 avl_for_each_element(&patterns, ev, avl) { 165 const char *key = ev->avl.key; 166 int cur_match_len; 167 bool full_match; 168 169 full_match = ubus_strmatch_len(id, key, &cur_match_len); 170 if (cur_match_len < match_len) 171 break; 172 173 match_len = cur_match_len; 174 175 if (!full_match) { 176 if (!ev->partial) 177 continue; 178 179 if (match_len != (int) strlen(key)) 180 continue; 181 } 182 183 ret = ubusd_send_event_msg(&ub, cl, ev->obj, id, fill_cb, cb_priv); 184 if (ret) 185 break; 186 } 187 188 if (ub) 189 ubus_msg_free(ub); 190 191 return ret; 192 } 193 194 enum { 195 EVMSG_ID, 196 EVMSG_DATA, 197 EVMSG_LAST, 198 }; 199 200 static struct blobmsg_policy ev_policy[] = { 201 [EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING }, 202 [EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 203 }; 204 205 static struct ubus_msg_buf * 206 ubusd_create_event_from_msg(void *priv, const char *id) 207 { 208 struct blob_attr *msg = priv; 209 210 blob_buf_init(&b, 0); 211 blob_put_int32(&b, UBUS_ATTR_OBJID, 0); 212 blob_put_string(&b, UBUS_ATTR_METHOD, id); 213 blob_put(&b, UBUS_ATTR_DATA, blobmsg_data(msg), blobmsg_data_len(msg)); 214 215 return ubus_msg_new(b.head, blob_raw_len(b.head), true); 216 } 217 218 static int ubusd_forward_event(struct ubus_client *cl, struct blob_attr *msg) 219 { 220 struct blob_attr *data; 221 struct blob_attr *attr[EVMSG_LAST]; 222 const char *id; 223 224 if (!msg) 225 return UBUS_STATUS_INVALID_ARGUMENT; 226 227 blobmsg_parse(ev_policy, EVMSG_LAST, attr, blob_data(msg), blob_len(msg)); 228 if (!attr[EVMSG_ID] || !attr[EVMSG_DATA]) 229 return UBUS_STATUS_INVALID_ARGUMENT; 230 231 id = blobmsg_data(attr[EVMSG_ID]); 232 data = attr[EVMSG_DATA]; 233 234 if (!strncmp(id, "ubus.", 5)) 235 return UBUS_STATUS_PERMISSION_DENIED; 236 237 return ubusd_send_event(cl, id, ubusd_create_event_from_msg, data); 238 } 239 240 static int ubusd_event_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg) 241 { 242 if (!strcmp(method, "register")) 243 return ubusd_alloc_event_pattern(cl, msg); 244 245 if (!strcmp(method, "send")) 246 return ubusd_forward_event(cl, msg); 247 248 return UBUS_STATUS_INVALID_COMMAND; 249 } 250 251 static struct ubus_msg_buf * 252 ubusd_create_object_event_msg(void *priv, const char *id) 253 { 254 struct ubus_object *obj = priv; 255 void *s; 256 257 blob_buf_init(&b, 0); 258 blob_put_int32(&b, UBUS_ATTR_OBJID, 0); 259 blob_put_string(&b, UBUS_ATTR_METHOD, id); 260 s = blob_nest_start(&b, UBUS_ATTR_DATA); 261 blobmsg_add_u32(&b, "id", obj->id.id); 262 blobmsg_add_string(&b, "path", obj->path.key); 263 blob_nest_end(&b, s); 264 265 return ubus_msg_new(b.head, blob_raw_len(b.head), true); 266 } 267 268 void ubusd_send_obj_event(struct ubus_object *obj, bool add) 269 { 270 const char *id = add ? "ubus.object.add" : "ubus.object.remove"; 271 272 ubusd_send_event(NULL, id, ubusd_create_object_event_msg, obj); 273 } 274 275 void ubusd_event_init(void) 276 { 277 ubus_init_string_tree(&patterns, true); 278 event_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_EVENT); 279 if (event_obj != NULL) 280 event_obj->recv_msg = ubusd_event_recv; 281 } 282 283
This page was automatically generated by LXR 0.3.1. • OpenWrt