X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;f=libubus.c;h=6291e757792e517b31a57805dc3f3b2874873065;hb=7864896a1bfbc27764de4c13ff7dfa762e4b71c7;hp=590a0fa2ec5dbdf6e008545c0b19bc4f421e640d;hpb=c6f705451527e6e5e8f5a2715f11478eeb8799e4;p=project%2Fubus.git diff --git a/libubus.c b/libubus.c index 590a0fa..6291e75 100644 --- a/libubus.c +++ b/libubus.c @@ -38,6 +38,7 @@ const char *__ubus_strerror[__UBUS_STATUS_LAST] = { [UBUS_STATUS_TIMEOUT] = "Request timed out", [UBUS_STATUS_NOT_SUPPORTED] = "Operation not supported", [UBUS_STATUS_UNKNOWN_ERROR] = "Unknown error", + [UBUS_STATUS_CONNECTION_FAILED] = "Connection failed", }; static struct blob_buf b; @@ -341,11 +342,18 @@ static struct ubus_request *ubus_find_request(struct ubus_context *ctx, uint32_t return NULL; } +void ubus_complete_deferred_request(struct ubus_context *ctx, struct ubus_request_data *req, int ret) +{ + blob_buf_init(&b, 0); + blob_put_int32(&b, UBUS_ATTR_STATUS, ret); + blob_put_int32(&b, UBUS_ATTR_OBJID, req->object); + ubus_send_msg(ctx, req->seq, b.head, UBUS_MSG_STATUS, req->peer); +} + static void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr) { struct ubus_request_data req; struct ubus_object *obj; - uint32_t objid = 0; int method; int ret = 0; @@ -356,14 +364,14 @@ static void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hd if (!attrbuf[UBUS_ATTR_OBJID]) return; - objid = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]); + req.object = blob_get_u32(attrbuf[UBUS_ATTR_OBJID]); if (!attrbuf[UBUS_ATTR_METHOD]) { ret = UBUS_STATUS_INVALID_ARGUMENT; goto send; } - obj = avl_find_element(&ctx->objects, &objid, obj, avl); + obj = avl_find_element(&ctx->objects, &req.object, obj, avl); if (!obj) { ret = UBUS_STATUS_NOT_FOUND; goto send; @@ -380,16 +388,14 @@ static void ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hd goto send; found: - req.object = objid; ret = obj->methods[method].handler(ctx, obj, &req, blob_data(attrbuf[UBUS_ATTR_METHOD]), attrbuf[UBUS_ATTR_DATA]); + if (req.deferred) + return; send: - blob_buf_init(&b, 0); - blob_put_int32(&b, UBUS_ATTR_STATUS, ret); - blob_put_int32(&b, UBUS_ATTR_OBJID, objid); - ubus_send_msg(ctx, req.seq, b.head, UBUS_MSG_STATUS, req.peer); + ubus_complete_deferred_request(ctx, &req, ret); } static void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr *hdr) @@ -922,75 +928,108 @@ int ubus_send_event(struct ubus_context *ctx, const char *id, return ubus_complete_request(ctx, &req, 0); } -static void ubus_default_connection_lost(struct ubus_context *ctx) +static void +ubus_refresh_state(struct ubus_context *ctx) { - if (ctx->sock.registered) - uloop_end(); + struct ubus_object *obj, *tmp; + + /* clear all type IDs, they need to be registered again */ + avl_for_each_element(&ctx->objects, obj, avl) + obj->type->id = 0; + + /* push out all objects again */ + avl_for_each_element_safe(&ctx->objects, obj, avl, tmp) { + obj->id = 0; + avl_delete(&ctx->objects, &obj->avl); + ubus_add_object(ctx, obj); + } } -struct ubus_context *ubus_connect(const char *path) +int ubus_reconnect(struct ubus_context *ctx, const char *path) { - struct ubus_context *ctx; struct { struct ubus_msghdr hdr; struct blob_attr data; } hdr; struct blob_attr *buf; + int ret = UBUS_STATUS_UNKNOWN_ERROR; if (!path) path = UBUS_UNIX_SOCKET; - ctx = calloc(1, sizeof(*ctx)); - if (!ctx) - goto error; + if (ctx->sock.fd >= 0) { + if (ctx->sock.registered) + uloop_fd_delete(&ctx->sock); + + close(ctx->sock.fd); + } ctx->sock.fd = usock(USOCK_UNIX, path, NULL); if (ctx->sock.fd < 0) - goto error_free; - - ctx->sock.cb = ubus_handle_data; + return UBUS_STATUS_CONNECTION_FAILED; if (read(ctx->sock.fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - goto error_close; + goto out_close; if (!ubus_validate_hdr(&hdr.hdr)) - goto error_close; + goto out_close; if (hdr.hdr.type != UBUS_MSG_HELLO) - goto error_close; + goto out_close; buf = calloc(1, blob_raw_len(&hdr.data)); if (!buf) - goto error_close; + goto out_close; memcpy(buf, &hdr.data, sizeof(hdr.data)); if (read(ctx->sock.fd, blob_data(buf), blob_len(buf)) != blob_len(buf)) - goto error_free_buf; + goto out_free; ctx->local_id = hdr.hdr.peer; + if (!ctx->local_id) + goto out_free; + + ret = UBUS_STATUS_OK; + fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK); + + ubus_refresh_state(ctx); + +out_free: free(buf); +out_close: + if (ret) + close(ctx->sock.fd); + + return ret; +} + +static void ubus_default_connection_lost(struct ubus_context *ctx) +{ + if (ctx->sock.registered) + uloop_end(); +} + +struct ubus_context *ubus_connect(const char *path) +{ + struct ubus_context *ctx; + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->sock.fd = -1; + ctx->sock.cb = ubus_handle_data; 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) - goto error_close; - - fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK); + if (ubus_reconnect(ctx, path)) { + free(ctx); + ctx = NULL; + } return ctx; - -error_free_buf: - free(buf); -error_close: - close(ctx->sock.fd); -error_free: - free(ctx); -error: - return NULL; } void ubus_free(struct ubus_context *ctx)