diff --git a/libubus.c b/libubus.c index 590a0fa..5488f3b 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; @@ -922,6 +923,81 @@ int ubus_send_event(struct ubus_context *ctx, const char *id, return ubus_complete_request(ctx, &req, 0); } +static void +ubus_refresh_state(struct ubus_context *ctx) +{ + 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); + } +} + +int ubus_reconnect(struct ubus_context *ctx, const char *path) +{ + 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; + + 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) + return UBUS_STATUS_CONNECTION_FAILED; + + if (read(ctx->sock.fd, &hdr, sizeof(hdr)) != sizeof(hdr)) + goto out_close; + + if (!ubus_validate_hdr(&hdr.hdr)) + goto out_close; + + if (hdr.hdr.type != UBUS_MSG_HELLO) + goto out_close; + + buf = calloc(1, blob_raw_len(&hdr.data)); + if (!buf) + 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 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) @@ -931,66 +1007,24 @@ static void ubus_default_connection_lost(struct ubus_context *ctx) struct ubus_context *ubus_connect(const char *path) { struct ubus_context *ctx; - struct { - struct ubus_msghdr hdr; - struct blob_attr data; - } hdr; - struct blob_attr *buf; - - if (!path) - path = UBUS_UNIX_SOCKET; ctx = calloc(1, sizeof(*ctx)); if (!ctx) - goto error; - - ctx->sock.fd = usock(USOCK_UNIX, path, NULL); - if (ctx->sock.fd < 0) - goto error_free; + return NULL; + ctx->sock.fd = -1; ctx->sock.cb = ubus_handle_data; - - if (read(ctx->sock.fd, &hdr, sizeof(hdr)) != sizeof(hdr)) - goto error_close; - - if (!ubus_validate_hdr(&hdr.hdr)) - goto error_close; - - if (hdr.hdr.type != UBUS_MSG_HELLO) - goto error_close; - - buf = calloc(1, blob_raw_len(&hdr.data)); - if (!buf) - goto error_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; - - ctx->local_id = hdr.hdr.peer; - free(buf); - 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) diff --git a/libubus.h b/libubus.h index 13e4c03..917d122 100644 --- a/libubus.h +++ b/libubus.h @@ -153,6 +153,7 @@ struct ubus_request { struct ubus_context *ubus_connect(const char *path); +int ubus_reconnect(struct ubus_context *ctx, const char *path); void ubus_free(struct ubus_context *ctx); const char *ubus_strerror(int error); diff --git a/ubusmsg.h b/ubusmsg.h index 607ecd4..10f84db 100644 --- a/ubusmsg.h +++ b/ubusmsg.h @@ -92,6 +92,7 @@ enum ubus_msg_status { UBUS_STATUS_TIMEOUT, UBUS_STATUS_NOT_SUPPORTED, UBUS_STATUS_UNKNOWN_ERROR, + UBUS_STATUS_CONNECTION_FAILED, __UBUS_STATUS_LAST };