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 (pattern[len - 1] == '*') { 88 partial = true; 89 pattern[len - 1] = 0; 90 len--; 91 } 92 93 if (pattern[0] && ubusd_acl_check(cl, pattern, NULL, UBUS_ACL_LISTEN)) 94 return UBUS_STATUS_PERMISSION_DENIED; 95 96 ev = calloc(1, sizeof(*ev) + len + 1); 97 if (!ev) 98 return UBUS_STATUS_NO_DATA; 99 100 list_add(&ev->list, &obj->events); 101 ev->obj = obj; 102 ev->partial = partial; 103 name = (char *) (ev + 1); 104 strcpy(name, pattern); 105 ev->avl.key = name; 106 avl_insert(&patterns, &ev->avl); 107 108 return 0; 109 } 110 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) 114 { 115 uint32_t *objid_ptr; 116 117 /* do not loop back events */ 118 if (obj->client == cl) 119 return; 120 121 /* do not send duplicate events */ 122 if (obj->event_seen == obj_event_seq) 123 return; 124 125 obj->event_seen = obj_event_seq; 126 127 if (!*ub) { 128 *ub = fill_cb(cb_priv, id); 129 (*ub)->hdr.type = UBUS_MSG_INVOKE; 130 (*ub)->hdr.peer = 0; 131 } 132 133 objid_ptr = blob_data(blob_data((*ub)->data)); 134 *objid_ptr = htonl(obj->id.id); 135 136 (*ub)->hdr.seq = ++event_seq; 137 ubus_msg_send(obj->client, *ub); 138 } 139 140 int ubusd_send_event(struct ubus_client *cl, const char *id, 141 event_fill_cb fill_cb, void *cb_priv) 142 { 143 struct ubus_msg_buf *ub = NULL; 144 struct event_source *ev; 145 int match_len = 0; 146 147 if (ubusd_acl_check(cl, id, NULL, UBUS_ACL_SEND)) 148 return UBUS_STATUS_PERMISSION_DENIED; 149 150 obj_event_seq++; 151 152 /* 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. 156 */ 157 avl_for_each_element(&patterns, ev, avl) { 158 const char *key = ev->avl.key; 159 int cur_match_len; 160 bool full_match; 161 162 full_match = ubus_strmatch_len(id, key, &cur_match_len); 163 if (cur_match_len < match_len) 164 break; 165 166 match_len = cur_match_len; 167 168 if (!full_match) { 169 if (!ev->partial) 170 continue; 171 172 if (match_len != (int) strlen(key)) 173 continue; 174 } 175 176 ubusd_send_event_msg(&ub, cl, ev->obj, id, fill_cb, cb_priv); 177 } 178 179 if (ub) 180 ubus_msg_free(ub); 181 182 return 0; 183 } 184 185 enum { 186 EVMSG_ID, 187 EVMSG_DATA, 188 EVMSG_LAST, 189 }; 190 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 }, 194 }; 195 196 static struct ubus_msg_buf * 197 ubusd_create_event_from_msg(void *priv, const char *id) 198 { 199 struct blob_attr *msg = priv; 200 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)); 205 206 return ubus_msg_new(b.head, blob_raw_len(b.head), true); 207 } 208 209 static int ubusd_forward_event(struct ubus_client *cl, struct blob_attr *msg) 210 { 211 struct blob_attr *data; 212 struct blob_attr *attr[EVMSG_LAST]; 213 const char *id; 214 215 if (!msg) 216 return UBUS_STATUS_INVALID_ARGUMENT; 217 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; 221 222 id = blobmsg_data(attr[EVMSG_ID]); 223 data = attr[EVMSG_DATA]; 224 225 if (!strncmp(id, "ubus.", 5)) 226 return UBUS_STATUS_PERMISSION_DENIED; 227 228 return ubusd_send_event(cl, id, ubusd_create_event_from_msg, data); 229 } 230 231 static int ubusd_event_recv(struct ubus_client *cl, struct ubus_msg_buf *ub, const char *method, struct blob_attr *msg) 232 { 233 if (!strcmp(method, "register")) 234 return ubusd_alloc_event_pattern(cl, msg); 235 236 if (!strcmp(method, "send")) 237 return ubusd_forward_event(cl, msg); 238 239 return UBUS_STATUS_INVALID_COMMAND; 240 } 241 242 static struct ubus_msg_buf * 243 ubusd_create_object_event_msg(void *priv, const char *id) 244 { 245 struct ubus_object *obj = priv; 246 void *s; 247 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); 255 256 return ubus_msg_new(b.head, blob_raw_len(b.head), true); 257 } 258 259 void ubusd_send_obj_event(struct ubus_object *obj, bool add) 260 { 261 const char *id = add ? "ubus.object.add" : "ubus.object.remove"; 262 263 ubusd_send_event(NULL, id, ubusd_create_object_event_msg, obj); 264 } 265 266 void ubusd_event_init(void) 267 { 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; 272 } 273 274
This page was automatically generated by LXR 0.3.1. • OpenWrt