• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ubus/libubus-obj.c

  1 /*
  2  * Copyright (C) 2011-2012 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 <unistd.h>
 15 #include "libubus.h"
 16 #include "libubus-internal.h"
 17 
 18 static void
 19 ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr,
 20                          struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
 21 {
 22         struct ubus_subscriber *s;
 23 
 24         if (!obj || !attrbuf[UBUS_ATTR_TARGET])
 25                 return;
 26 
 27         if (obj->methods != &watch_method)
 28                 return;
 29 
 30         s = container_of(obj, struct ubus_subscriber, obj);
 31         if (s->remove_cb)
 32                 s->remove_cb(ctx, s, blob_get_u32(attrbuf[UBUS_ATTR_TARGET]));
 33 
 34         if (fd >= 0)
 35                 close(fd);
 36 }
 37 
 38 static void
 39 ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr,
 40                     struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
 41 {
 42         if (!obj || !attrbuf[UBUS_ATTR_ACTIVE])
 43                 return;
 44 
 45         obj->has_subscribers = blob_get_u8(attrbuf[UBUS_ATTR_ACTIVE]);
 46         if (obj->subscribe_cb)
 47                 obj->subscribe_cb(ctx, obj);
 48 
 49         if (fd >= 0)
 50                 close(fd);
 51 }
 52 static void
 53 ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr,
 54                     struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
 55 {
 56         struct ubus_request_data req = {
 57                 .fd = -1,
 58                 .req_fd = fd,
 59         };
 60         ubus_handler_t handler;
 61         int method;
 62         int ret;
 63         bool no_reply = false;
 64 
 65         if ((!obj && !ubus_context_is_channel(ctx)) ||
 66             (!ctx->request_handler && ubus_context_is_channel(ctx))) {
 67                 ret = UBUS_STATUS_NOT_FOUND;
 68                 goto send;
 69         }
 70 
 71         if (!attrbuf[UBUS_ATTR_METHOD]) {
 72                 ret = UBUS_STATUS_INVALID_ARGUMENT;
 73                 goto send;
 74         }
 75 
 76         if (attrbuf[UBUS_ATTR_NO_REPLY])
 77                 no_reply = blob_get_int8(attrbuf[UBUS_ATTR_NO_REPLY]);
 78 
 79         req.peer = hdr->peer;
 80         req.seq = hdr->seq;
 81 
 82         if (ubus_context_is_channel(ctx)) {
 83                 handler = ctx->request_handler;
 84                 goto found;
 85         }
 86 
 87         req.object = obj->id;
 88         if (attrbuf[UBUS_ATTR_USER] && attrbuf[UBUS_ATTR_GROUP]) {
 89                 req.acl.user = blobmsg_get_string(attrbuf[UBUS_ATTR_USER]);
 90                 req.acl.group = blobmsg_get_string(attrbuf[UBUS_ATTR_GROUP]);
 91                 req.acl.object = obj->name;
 92         }
 93         for (method = 0; method < obj->n_methods; method++)
 94                 if (!obj->methods[method].name ||
 95                     !strcmp(obj->methods[method].name,
 96                             blob_data(attrbuf[UBUS_ATTR_METHOD]))) {
 97                         handler = obj->methods[method].handler;
 98                         goto found;
 99                 }
100 
101         /* not found */
102         ret = UBUS_STATUS_METHOD_NOT_FOUND;
103         goto send;
104 
105 found:
106         if (!attrbuf[UBUS_ATTR_DATA]) {
107                 ret = UBUS_STATUS_INVALID_ARGUMENT;
108                 goto send;
109         }
110 
111         ret = handler(ctx, obj, &req, blob_data(attrbuf[UBUS_ATTR_METHOD]),
112                       attrbuf[UBUS_ATTR_DATA]);
113         if (req.req_fd >= 0)
114                 close(req.req_fd);
115         if (req.deferred || no_reply)
116                 return;
117 
118 send:
119         ubus_complete_deferred_request(ctx, &req, ret);
120 }
121 
122 
123 void __hidden ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd)
124 {
125         void (*cb)(struct ubus_context *, struct ubus_msghdr *,
126                    struct ubus_object *, struct blob_attr **, int fd);
127         struct ubus_msghdr *hdr = &buf->hdr;
128         struct blob_attr **attrbuf;
129         struct ubus_object *obj;
130         uint32_t objid;
131         void *prev_data = NULL;
132         attrbuf = ubus_parse_msg(buf->data, blob_raw_len(buf->data));
133         if (!attrbuf[UBUS_ATTR_OBJID])
134                 return;
135 
136         objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
137         obj = avl_find_element(&ctx->objects, &objid, obj, avl);
138 
139         switch (hdr->type) {
140         case UBUS_MSG_INVOKE:
141                 cb = ubus_process_invoke;
142                 break;
143         case UBUS_MSG_UNSUBSCRIBE:
144                 cb = ubus_process_unsubscribe;
145                 break;
146         case UBUS_MSG_NOTIFY:
147                 cb = ubus_process_notify;
148                 break;
149         default:
150                 return;
151         }
152 
153         if (buf == &ctx->msgbuf) {
154                 prev_data = buf->data;
155                 buf->data = NULL;
156         }
157 
158         cb(ctx, hdr, obj, attrbuf, fd);
159 
160         if (prev_data) {
161                 if (buf->data)
162                         free(prev_data);
163                 else
164                         buf->data = prev_data;
165         }
166 }
167 
168 static void ubus_add_object_cb(struct ubus_request *req, int type, struct blob_attr *msg)
169 {
170         struct ubus_object *obj = req->priv;
171         struct blob_attr **attrbuf = ubus_parse_msg(msg, blob_raw_len(msg));
172 
173         if (!attrbuf[UBUS_ATTR_OBJID])
174                 return;
175 
176         obj->id = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
177 
178         if (attrbuf[UBUS_ATTR_OBJTYPE])
179                 obj->type->id = blob_get_u32(attrbuf[UBUS_ATTR_OBJTYPE]);
180 
181         obj->avl.key = &obj->id;
182         avl_insert(&req->ctx->objects, &obj->avl);
183 }
184 
185 static void ubus_push_method_data(const struct ubus_method *m)
186 {
187         void *mtbl;
188         int i;
189 
190         mtbl = blobmsg_open_table(&b, m->name);
191 
192         for (i = 0; i < m->n_policy; i++) {
193                 if (m->mask && !(m->mask & (1 << i)))
194                         continue;
195 
196                 blobmsg_add_u32(&b, m->policy[i].name, m->policy[i].type);
197         }
198 
199         blobmsg_close_table(&b, mtbl);
200 }
201 
202 static bool ubus_push_object_type(const struct ubus_object_type *type)
203 {
204         void *s;
205         int i;
206 
207         s = blob_nest_start(&b, UBUS_ATTR_SIGNATURE);
208 
209         for (i = 0; i < type->n_methods; i++)
210                 ubus_push_method_data(&type->methods[i]);
211 
212         blob_nest_end(&b, s);
213 
214         return true;
215 }
216 
217 int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj)
218 {
219         struct ubus_request req;
220         int ret;
221 
222         if (ubus_context_is_channel(ctx))
223                 return UBUS_STATUS_INVALID_ARGUMENT;
224 
225         blob_buf_init(&b, 0);
226 
227         if (obj->name && obj->type) {
228                 blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->name);
229 
230                 if (obj->type->id)
231                         blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id);
232                 else if (!ubus_push_object_type(obj->type))
233                         return UBUS_STATUS_INVALID_ARGUMENT;
234         }
235 
236         if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_ADD_OBJECT, 0) < 0)
237                 return UBUS_STATUS_INVALID_ARGUMENT;
238 
239         req.raw_data_cb = ubus_add_object_cb;
240         req.priv = obj;
241         ret = ubus_complete_request(ctx, &req, 0);
242         if (ret)
243                 return ret;
244 
245         if (!obj->id)
246                 return UBUS_STATUS_NO_DATA;
247 
248         return 0;
249 }
250 
251 static void ubus_remove_object_cb(struct ubus_request *req, int type, struct blob_attr *msg)
252 {
253         struct ubus_object *obj = req->priv;
254         struct blob_attr **attrbuf = ubus_parse_msg(msg, blob_raw_len(msg));
255 
256         if (!attrbuf[UBUS_ATTR_OBJID])
257                 return;
258 
259         avl_delete(&req->ctx->objects, &obj->avl);
260 
261         obj->id = 0;
262 
263         if (attrbuf[UBUS_ATTR_OBJTYPE] && obj->type)
264                 obj->type->id = 0;
265 }
266 
267 int ubus_remove_object(struct ubus_context *ctx, struct ubus_object *obj)
268 {
269         struct ubus_request req;
270         int ret;
271 
272         if (ubus_context_is_channel(ctx))
273                 return UBUS_STATUS_INVALID_ARGUMENT;
274 
275         blob_buf_init(&b, 0);
276         blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id);
277 
278         if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_REMOVE_OBJECT, 0) < 0)
279                 return UBUS_STATUS_INVALID_ARGUMENT;
280 
281         req.raw_data_cb = ubus_remove_object_cb;
282         req.priv = obj;
283         ret = ubus_complete_request(ctx, &req, 0);
284         if (ret)
285                 return ret;
286 
287         if (obj->id)
288                 return UBUS_STATUS_NO_DATA;
289 
290         return 0;
291 }
292 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt