X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fubus.git;a=blobdiff_plain;f=libubus.c;h=590a0fa2ec5dbdf6e008545c0b19bc4f421e640d;hp=f3859b7e6eb8fb84987858a599b4823701cb1a43;hb=95062c1ef74695d138bbc4b9efc5910b1436bd9c;hpb=1ad3493658fe3a3782e51efe960c07549f117a28 diff --git a/libubus.c b/libubus.c index f3859b7..590a0fa 100644 --- a/libubus.c +++ b/libubus.c @@ -56,6 +56,13 @@ struct ubus_pending_data { struct blob_attr data[]; }; +struct ubus_pending_invoke { + struct list_head list; + struct ubus_msghdr hdr; +}; + +static void ubus_process_pending_invoke(struct ubus_context *ctx); + static int ubus_cmp_id(const void *k1, const void *k2, void *ptr) { const uint32_t *id1 = k1, *id2 = k2; @@ -282,7 +289,7 @@ static int ubus_process_req_status(struct ubus_request *req, struct ubus_msghdr int ret = UBUS_STATUS_INVALID_ARGUMENT; if (!list_empty(&req->list)) - list_del(&req->list); + list_del_init(&req->list); ubus_get_status(hdr, &ret); req->peer = hdr->peer; @@ -387,6 +394,7 @@ send: static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr) { + struct ubus_pending_invoke *pending; struct ubus_request *req; switch(hdr->type) { @@ -405,11 +413,36 @@ static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr) break; case UBUS_MSG_INVOKE: - ubus_process_invoke(ctx, hdr); + if (ctx->stack_depth > 2) { + pending = calloc(1, sizeof(*pending) + + blob_raw_len(hdr->data)); + + if (!pending) + return; + + memcpy(&pending->hdr, hdr, sizeof(*hdr) + + blob_raw_len(hdr->data)); + list_add(&pending->list, &ctx->pending); + } else { + ubus_process_invoke(ctx, hdr); + } break; } } +static void ubus_process_pending_invoke(struct ubus_context *ctx) +{ + struct ubus_pending_invoke *pending, *tmp; + + list_for_each_entry_safe(pending, tmp, &ctx->pending, list) { + list_del(&pending->list); + ubus_process_msg(ctx, &pending->hdr); + free(pending); + if (ctx->stack_depth > 2) + break; + } +} + void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req) { if (!list_empty(&req->list)) @@ -417,7 +450,7 @@ void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req) req->cancelled = true; ubus_process_req_data(req); - list_del(&req->list); + list_del_init(&req->list); } void ubus_complete_request_async(struct ubus_context *ctx, struct ubus_request *req) @@ -469,7 +502,6 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req, struct ubus_sync_req_cb cb; ubus_complete_handler_t complete_cb = req->complete_cb; bool registered = ctx->sock.registered; - bool cancelled = uloop_cancelled; int status = UBUS_STATUS_NO_DATA; if (!registered) { @@ -487,7 +519,14 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req, ubus_complete_request_async(ctx, req); req->complete_cb = ubus_sync_req_cb; - uloop_run(); + ctx->stack_depth++; + while (!req->status_msg) { + bool cancelled = uloop_cancelled; + uloop_cancelled = false; + uloop_run(); + uloop_cancelled = cancelled; + } + ctx->stack_depth--; if (timeout) uloop_timeout_cancel(&cb.timeout); @@ -499,10 +538,12 @@ int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req, if (req->complete_cb) req->complete_cb(req, status); - uloop_cancelled = cancelled; if (!registered) uloop_fd_delete(&ctx->sock); + if (!ctx->stack_depth) + ubus_process_pending_invoke(ctx); + return status; } @@ -668,7 +709,7 @@ static bool ubus_push_object_type(const struct ubus_object_type *type) return true; } -static int __ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj) +int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj) { struct ubus_request req; int ret; @@ -699,14 +740,6 @@ static int __ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj) return 0; } -int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj) -{ - if (!obj->name || !obj->type) - return UBUS_STATUS_INVALID_ARGUMENT; - - return __ubus_add_object(ctx, obj); -} - static void ubus_remove_object_cb(struct ubus_request *req, int type, struct blob_attr *msg) { struct ubus_object *obj = req->priv; @@ -778,7 +811,7 @@ int ubus_register_event_handler(struct ubus_context *ctx, if (!!obj->name ^ !!obj->type) return UBUS_STATUS_INVALID_ARGUMENT; - ret = __ubus_add_object(ctx, obj); + ret = ubus_add_object(ctx, obj); if (ret) return ret; } @@ -794,6 +827,81 @@ int ubus_register_event_handler(struct ubus_context *ctx, NULL, NULL, 0); } +enum { + WATCH_ID, + WATCH_NOTIFY, + __WATCH_MAX +}; + +static const struct blobmsg_policy watch_policy[] = { + [WATCH_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, + [WATCH_NOTIFY] = { .name = "notify", .type = BLOBMSG_TYPE_STRING }, +}; + + +static int ubus_watch_cb(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, struct blob_attr *msg) +{ + struct ubus_watch_object *w; + struct blob_attr *tb[__WATCH_MAX]; + + blobmsg_parse(watch_policy, ARRAY_SIZE(watch_policy), tb, blob_data(msg), blob_len(msg)); + + if (!tb[WATCH_ID] || !tb[WATCH_NOTIFY]) + return UBUS_STATUS_INVALID_ARGUMENT; + + if (req->peer) + return UBUS_STATUS_INVALID_ARGUMENT; + + w = container_of(obj, struct ubus_watch_object, obj); + w->cb(ctx, w, blobmsg_get_u32(tb[WATCH_ID])); + return 0; +} + +static const struct ubus_method watch_method = { + .name = NULL, + .handler = ubus_watch_cb, +}; + +int ubus_register_watch_object(struct ubus_context *ctx, struct ubus_watch_object *w_obj) +{ + struct ubus_object *obj = &w_obj->obj; + + obj->methods = &watch_method; + obj->n_methods = 1; + + return ubus_add_object(ctx, obj); +} + +static int +__ubus_watch_request(struct ubus_context *ctx, struct ubus_object *obj, uint32_t id, const char *method, int type) +{ + struct ubus_request req; + + blob_buf_init(&b, 0); + blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id); + blob_put_int32(&b, UBUS_ATTR_TARGET, id); + if (method) + blob_put_string(&b, UBUS_ATTR_METHOD, method); + + if (ubus_start_request(ctx, &req, b.head, type, 0) < 0) + return UBUS_STATUS_INVALID_ARGUMENT; + + return ubus_complete_request(ctx, &req, 0); + +} + +int ubus_watch_object_add(struct ubus_context *ctx, struct ubus_watch_object *obj, uint32_t id) +{ + return __ubus_watch_request(ctx, &obj->obj, id, "event", UBUS_MSG_ADD_WATCH); +} + +int ubus_watch_object_remove(struct ubus_context *ctx, struct ubus_watch_object *obj, uint32_t id) +{ + return __ubus_watch_request(ctx, &obj->obj, id, NULL, UBUS_MSG_REMOVE_WATCH); +} + int ubus_send_event(struct ubus_context *ctx, const char *id, struct blob_attr *data) { @@ -865,6 +973,7 @@ struct ubus_context *ubus_connect(const char *path) ctx->connection_lost = ubus_default_connection_lost; INIT_LIST_HEAD(&ctx->requests); + INIT_LIST_HEAD(&ctx->pending); avl_init(&ctx->objects, ubus_cmp_id, false, NULL); if (!ctx->local_id)