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 int 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 int 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 <= 0) 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 void 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; 123 124 /* do not send duplicate events */ 125 if (obj->event_seen == obj_event_seq) 126 return; 127 128 obj->event_seen = obj_event_seq; 129 130 if (!*ub) { 131 *ub = fill_cb(cb_priv, id); 132 (*ub)->hdr.type = UBUS_MSG_INVOKE; 133 (*ub)->hdr.peer = 0; 134 } 135 136 objid_ptr = blob_data(blob_data((*ub)->data)); 137 *objid_ptr = htonl(obj->id.id); 138 139 (*ub)->hdr.seq = ++event_seq; 140 ubus_msg_send(obj->client, *ub); 141 } 142 143 int ubusd_send_event(struct ubus_client *cl, const char *id, 144 event_fill_cb fill_cb, void *cb_priv) 145 { 146 struct ubus_msg_buf *ub = NULL; 147 struct event_source *ev; 148 int match_len = 0; 149 150 if (ubusd_acl_check(cl, id, NULL, UBUS_ACL_SEND)) 151 return UBUS_STATUS_PERMISSION_DENIED; 152 153 obj_event_seq++; 154 155 /* 156 * Since this tree is sorted alphabetically, we can only expect to find 157 * matching entries as long as the number of matching characters 158 * between the pattern string and our string is monotonically increasing. 159 */ 160 avl_for_each_element(&patterns, ev, avl) { 161 const char *key = ev->avl.key; 162 int cur_match_len; 163 bool full_match; 164 165 full_match = ubus_strmatch_len(id, key, &cur_match_len); 166 if (cur_match_len < match_len) 167 break; 168 169 match_len = cur_match_len; 170 171 if (!full_match) { 172 if (!ev->partial) 173 continue; 174 175 if (match_len != (int) strlen(key)) 176 continue; 177 } 178 179 ubusd_send_event_msg(&ub, cl, ev->obj, id, fill_cb, cb_priv); 180 } 181 182 if (ub) 183 ubus_msg_free(ub); 184 185 return 0; 186 } 187 188 enum { 189 EVMSG_ID, 190 EVMSG_DATA, 191 EVMSG_LAST, 192 }; 193 194 static struct blobmsg_policy ev_policy[] = { 195 [EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING }, 196 [EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE }, 197 }; 198 199 static struct ubus_msg_buf * 200 ubusd_create_event_from_msg(void *priv, const char *id) 201 { 202 struct blob_attr *msg = priv; 203 204 blob_buf_init(&b, 0); 205 blob_put_int32(&b, UBUS_ATTR_OBJID, 0); 206 blob_put_string(&b, UBUS_ATTR_METHOD, id); 207 blob_put(&b, UBUS_ATTR_DATA, blobmsg_data(msg), blobmsg_data_len(msg)); 208 209 return ubus_msg_new(b.head, blob_raw_len(b.head), true); 210 } 211 212 static int ubusd_forward_event(struct ubus_client *cl, struct blob_attr *msg) 213 { 214 struct blob_attr *data; 215 struct blob_attr *attr[EVMSG_LAST]; 216 const char *id; 217 218 if (!msg) 219 return UBUS_STATUS_INVALID_ARGUMENT; 220 221 blobmsg_parse(ev_policy, EVMSG_LAST, attr, blob_data(msg), blob_len(msg)); 222 if (!attr[EVMSG_ID] || !attr[EVMSG_DATA]) 223 return UBUS_STATUS_INVALID_ARGUMENT; 224 225 id = blobmsg_data(attr[EVMSG_ID]); 226 data = attr[EVMSG_DATA]; 227 228 if (!strncmp(id, "ubus.", 5)) 229 return UBUS_STATUS_PERMISSION_DENIED; 230 231 return ubusd_send_event(cl, id, ubusd_create_event_from_msg, data); 232 } 233 234 static int ubusd_event_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg) 235 { 236 if (!strcmp(method, "register")) 237 return ubusd_alloc_event_pattern(cl, msg); 238 239 if (!strcmp(method, "send")) 240 return ubusd_forward_event(cl, msg); 241 242 return UBUS_STATUS_INVALID_COMMAND; 243 } 244 245 static struct ubus_msg_buf * 246 ubusd_create_object_event_msg(void *priv, const char *id) 247 { 248 struct ubus_object *obj = priv; 249 void *s; 250 251 blob_buf_init(&b, 0); 252 blob_put_int32(&b, UBUS_ATTR_OBJID, 0); 253 blob_put_string(&b, UBUS_ATTR_METHOD, id); 254 s = blob_nest_start(&b, UBUS_ATTR_DATA); 255 blobmsg_add_u32(&b, "id", obj->id.id); 256 blobmsg_add_string(&b, "path", obj->path.key); 257 blob_nest_end(&b, s); 258 259 return ubus_msg_new(b.head, blob_raw_len(b.head), true); 260 } 261 262 void ubusd_send_obj_event(struct ubus_object *obj, bool add) 263 { 264 const char *id = add ? "ubus.object.add" : "ubus.object.remove"; 265 266 ubusd_send_event(NULL, id, ubusd_create_object_event_msg, obj); 267 } 268 269 void ubusd_event_init(void) 270 { 271 ubus_init_string_tree(&patterns, true); 272 event_obj = ubusd_create_object_internal(NULL, UBUS_SYSTEM_OBJECT_EVENT); 273 if (event_obj != NULL) 274 event_obj->recv_msg = ubusd_event_recv; 275 } 276 277
This page was automatically generated by LXR 0.3.1. • OpenWrt