libubus: add support for reconnecting (and re-publishing objects)
authorFelix Fietkau <nbd@openwrt.org>
Mon, 28 May 2012 22:56:37 +0000 (00:56 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 28 May 2012 22:56:37 +0000 (00:56 +0200)
libubus.c
libubus.h
ubusmsg.h

index 590a0fa2ec5dbdf6e008545c0b19bc4f421e640d..5488f3b8dcc6c1f05ed0250aa3bbe2c19ec18e0c 100644 (file)
--- 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,75 +923,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)
index 13e4c030b945b3f206ad8a52b259c812d6504e16..917d1221e3d2808a3b3ec5daaa8cbfa1e01bba37 100644 (file)
--- 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);
index 607ecd4ac71ef21f0a0c972a748ee0714061c0ae..10f84db2045f99f2532beea2e7ab65c5426a9dcf 100644 (file)
--- 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
 };