Browse Source

libubus: add support for reconnecting (and re-publishing objects)

Felix Fietkau 12 years ago
parent
commit
34161692fa
3 changed files with 66 additions and 30 deletions
  1. 64 30
      libubus.c
  2. 1 0
      libubus.h
  3. 1 0
      ubusmsg.h

+ 64 - 30
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)

+ 1 - 0
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);

+ 1 - 0
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
 };