libubus: reduce code duplication and add stack depth protection for unsubscribe/notify callbacks

Signed-off-by: Felix Fietkau <nbd@openwrt.org>
This commit is contained in:
Felix Fietkau 2012-12-14 13:42:10 +01:00
parent 0fccce4445
commit 7cd33a8e3a
4 changed files with 75 additions and 72 deletions

View file

@ -23,10 +23,9 @@ void ubus_handle_data(struct uloop_fd *u, unsigned int events);
int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
struct blob_attr *msg, int cmd, uint32_t peer);
void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr);
void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr);
int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
struct blob_attr *msg, int cmd, uint32_t peer);
void ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr);
void ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr);
void ubus_process_obj_msg(struct ubus_context*ctx, struct ubus_msghdr *hdr);
extern const struct ubus_method watch_method;
#endif

View file

@ -14,33 +14,54 @@
#include "libubus.h"
#include "libubus-internal.h"
void __hidden ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr)
static void
ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr,
struct ubus_object *obj, struct blob_attr **attrbuf)
{
struct blob_attr **attrbuf;
struct ubus_request_data req = {};
struct ubus_object *obj;
int method;
int ret = 0;
struct ubus_subscriber *s;
req.peer = hdr->peer;
req.seq = hdr->seq;
attrbuf = ubus_parse_msg(hdr->data);
if (!attrbuf[UBUS_ATTR_OBJID])
if (!obj || !attrbuf[UBUS_ATTR_TARGET])
return;
req.object = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
if (obj->methods != &watch_method)
return;
s = container_of(obj, struct ubus_subscriber, obj);
s->remove_cb(ctx, s, blob_get_u32(attrbuf[UBUS_ATTR_TARGET]));
}
static void
ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr,
struct ubus_object *obj, struct blob_attr **attrbuf)
{
if (!obj || !attrbuf[UBUS_ATTR_ACTIVE])
return;
obj->has_subscribers = blob_get_u8(attrbuf[UBUS_ATTR_ACTIVE]);
if (obj->subscribe_cb)
obj->subscribe_cb(ctx, obj);
}
static void
ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr,
struct ubus_object *obj, struct blob_attr **attrbuf)
{
struct ubus_request_data req = {};
int method;
int ret;
if (!obj) {
ret = UBUS_STATUS_NOT_FOUND;
goto send;
}
if (!attrbuf[UBUS_ATTR_METHOD]) {
ret = UBUS_STATUS_INVALID_ARGUMENT;
goto send;
}
obj = avl_find_element(&ctx->objects, &req.object, obj, avl);
if (!obj) {
ret = UBUS_STATUS_NOT_FOUND;
goto send;
}
req.peer = hdr->peer;
req.seq = hdr->seq;
req.object = obj->id;
for (method = 0; method < obj->n_methods; method++)
if (!obj->methods[method].name ||
@ -63,6 +84,37 @@ send:
ubus_complete_deferred_request(ctx, &req, ret);
}
void __hidden ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr)
{
void (*cb)(struct ubus_context *, struct ubus_msghdr *,
struct ubus_object *, struct blob_attr **);
struct blob_attr **attrbuf;
struct ubus_object *obj;
uint32_t objid;
attrbuf = ubus_parse_msg(hdr->data);
if (!attrbuf[UBUS_ATTR_OBJID])
return;
objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
obj = avl_find_element(&ctx->objects, &objid, obj, avl);
switch (hdr->type) {
case UBUS_MSG_INVOKE:
cb = ubus_process_invoke;
break;
case UBUS_MSG_UNSUBSCRIBE:
cb = ubus_process_unsubscribe;
break;
case UBUS_MSG_NOTIFY:
cb = ubus_process_notify;
break;
default:
return;
}
cb(ctx, hdr, obj, attrbuf);
}
static void ubus_add_object_cb(struct ubus_request *req, int type, struct blob_attr *msg)
{
struct ubus_object *obj = req->priv;

View file

@ -25,7 +25,7 @@ static int ubus_subscriber_cb(struct ubus_context *ctx, struct ubus_object *obj,
return 0;
}
static const struct ubus_method watch_method = {
const struct ubus_method watch_method __hidden = {
.name = NULL,
.handler = ubus_subscriber_cb,
};
@ -66,45 +66,3 @@ int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint
return __ubus_subscribe_request(ctx, &obj->obj, id, UBUS_MSG_UNSUBSCRIBE);
}
void __hidden ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr)
{
struct ubus_subscriber *s;
struct blob_attr **attrbuf;
struct ubus_object *obj;
uint32_t objid;
attrbuf = ubus_parse_msg(hdr->data);
if (!attrbuf[UBUS_ATTR_OBJID] || !attrbuf[UBUS_ATTR_TARGET])
return;
objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
obj = avl_find_element(&ctx->objects, &objid, obj, avl);
if (!obj)
return;
if (obj->methods != &watch_method)
return;
s = container_of(obj, struct ubus_subscriber, obj);
s->remove_cb(ctx, s, blob_get_u32(attrbuf[UBUS_ATTR_TARGET]));
}
void __hidden ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr)
{
struct blob_attr **attrbuf;
struct ubus_object *obj;
uint32_t objid;
attrbuf = ubus_parse_msg(hdr->data);
if (!attrbuf[UBUS_ATTR_OBJID] || !attrbuf[UBUS_ATTR_ACTIVE])
return;
objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]);
obj = avl_find_element(&ctx->objects, &objid, obj, avl);
if (!obj)
return;
obj->has_subscribers = blob_get_u8(attrbuf[UBUS_ATTR_ACTIVE]);
if (obj->subscribe_cb)
obj->subscribe_cb(ctx, obj);
}

View file

@ -214,6 +214,8 @@ void __hidden ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr
break;
case UBUS_MSG_INVOKE:
case UBUS_MSG_UNSUBSCRIBE:
case UBUS_MSG_NOTIFY:
if (ctx->stack_depth > 2) {
pending = calloc(1, sizeof(*pending) +
blob_raw_len(hdr->data));
@ -225,17 +227,9 @@ void __hidden ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr
blob_raw_len(hdr->data));
list_add(&pending->list, &ctx->pending);
} else {
ubus_process_invoke(ctx, hdr);
ubus_process_obj_msg(ctx, hdr);
}
break;
case UBUS_MSG_UNSUBSCRIBE:
ubus_process_unsubscribe(ctx, hdr);
break;
case UBUS_MSG_NOTIFY:
ubus_process_notify(ctx, hdr);
break;
}
}