ubus 源码解析

ubus 源码解析

ubus 安装

sudo apt install lua5.1
sudo apt install liblua5.1-0-dev
sudo apt install libjson-c-dev
libubox
$ git clone git://git.openwrt.org/project/libubox.git
$ cd libubox
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install

ubus
$ git clone git://git.openwrt.org/project/ubus.git
$ cd ubus
$ mkdir build
$ cmake ..
$ make
$ sudo make install

blob blobmsg内存布局

blob_buf,blobmsg内存图详解

struct blob_attr {
	uint32_t id_len;
	char data[];
} __packed

struct blob_buf {
	struct blob_attr *head;
	bool (*grow)(struct blob_buf *buf, int minlen);
	int buflen;
	void *buf;
};

在这里插入图片描述
head指向头blob_attr, 当向blob_buf中添加blob_attr时,相当于继续填充头blob_attr的data区域。
头blob_attr类似嵌套结构中最外层的大括号。head存在的主要作用是实现嵌套结构,如table 和array结构。添加嵌套结构时,head暂存嵌套结构头。

int
blob_buf_init(struct blob_buf *buf, int id); 
初始化blob_buf,此时head和buf同指向头blob_attr,此时头blob_attr的data中没有数据。
struct blobmsg_hdr {
	uint16_t namelen;
	uint8_t name[];
} __packed;

ubusd

ubus 是使用epoll 来处理IO的很好的例子。
ubus_main.c 中

int main(int argc, char **argv)
{
	const char *ubus_socket = UBUS_UNIX_SOCKET;
	int ret = 0;
	int ch;

	signal(SIGPIPE, SIG_IGN);
	signal(SIGHUP, sighup_handler);

	openlog("ubusd", LOG_PID, LOG_DAEMON);
	uloop_init();

	while ((ch = getopt(argc, argv, "A:s:")) != -1) {
		switch (ch) {
		case 's':
			ubus_socket = optarg;
			break;
		case 'A':
			ubusd_acl_dir = optarg;
			break;
		default:
			return usage(argv[0]);
		}
	}

	mkdir_sockdir();
	unlink(ubus_socket);
	umask(0111);
	server_fd.fd = usock(USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK, ubus_socket, NULL);
	if (server_fd.fd < 0) {
		perror("usock");
		ret = -1;
		goto out;
	}
	uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
	ubusd_acl_load();

	uloop_run();
	unlink(ubus_socket);

out:
	uloop_done();
	return ret;
}

usock() 加上 USOCK_SERVER参数创建一个unix sock fd,使用的是TCP.
uloop_fd_add() 将server_fd 加入到epoll 多路IO监控器中。

uloop_run() 是处理IO的主函数

static inline int uloop_run(void)
{
	return uloop_run_timeout(-1);
}

int uloop_run_timeout(int timeout)
{
	int next_time = 0;
	struct timeval tv;

	uloop_run_depth++;

	uloop_status = 0;
	uloop_cancelled = false;
	while (!uloop_cancelled)
	{
		uloop_gettime(&tv);
		uloop_process_timeouts(&tv);

		if (do_sigchld)
			uloop_handle_processes();

		if (uloop_cancelled)
			break;

		uloop_gettime(&tv);

		next_time = uloop_get_next_timeout(&tv);
		if (timeout >= 0 && timeout < next_time)
			next_time = timeout;
		uloop_run_events(next_time);
	}

	--uloop_run_depth;

	return uloop_status;
}
static void uloop_process_timeouts(struct timeval *tv)
{
	struct uloop_timeout *t;

	while (!list_empty(&timeouts)) {
		t = list_first_entry(&timeouts, struct uloop_timeout, list);

		if (tv_diff(&t->time, tv) > 0)
			break;

		uloop_timeout_cancel(t);
		if (t->cb)
			t->cb(t);
	}
}

struct uloop_fd_stack {
	struct uloop_fd_stack *next;
	struct uloop_fd *fd;
	unsigned int events;
};
uloop_fd_event 包含fd信息和IO到来时的epoll事件 
struct uloop_fd_event {
	struct uloop_fd *fd;
	unsigned int events;
};

static int uloop_fetch_events(int timeout)
{
	int n, nfds;

	nfds = epoll_wait(poll_fd, events, ARRAY_SIZE(events), timeout);
	for (n = 0; n < nfds; ++n) {
		struct uloop_fd_event *cur = &cur_fds[n];
		struct uloop_fd *u = events[n].data.ptr;
		unsigned int ev = 0;

		cur->fd = u;
		if (!u)
			continue;

		if (events[n].events & (EPOLLERR|EPOLLHUP)) {
			u->error = true;
			if (!(u->flags & ULOOP_ERROR_CB))
				uloop_fd_delete(u);
		}

		if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP))) {
			cur->fd = NULL;
			continue;
		}

		if(events[n].events & EPOLLRDHUP)
			u->eof = true;

		if(events[n].events & EPOLLIN)
			ev |= ULOOP_READ;

		if(events[n].events & EPOLLOUT)
			ev |= ULOOP_WRITE;

		cur->events = ev;
	}

	return nfds;
}
static void uloop_run_events(int timeout)
{
	struct uloop_fd_event *cur;
	struct uloop_fd *fd;

	if (!cur_nfds) {
		cur_fd = 0;
		cur_nfds = uloop_fetch_events(timeout);
		if (cur_nfds < 0)
			cur_nfds = 0;
	}
同时获取到cur_nfds个准备好的IO
	while (cur_nfds > 0) {
		struct uloop_fd_stack stack_cur;
		unsigned int events;

		cur = &cur_fds[cur_fd++];
		cur_nfds--;

		fd = cur->fd;
		events = cur->events;
		if (!fd)
			continue;

		if (!fd->cb)
			continue;

		if (uloop_fd_stack_event(fd, cur->events))
			continue;

		stack_cur.next = fd_stack;
		stack_cur.fd = fd;
		fd_stack = &stack_cur;
		do {
			stack_cur.events = 0;
			fd->cb(fd, events);
			events = stack_cur.events & ULOOP_EVENT_MASK;
		} while (stack_cur.fd && events);
		fd_stack = stack_cur.next;

		return;
	}
}

使用uloop_fd管理fd的相关信息。

struct uloop_fd
{
	uloop_fd_handler cb;
	int fd;
	bool eof;
	bool error;
	bool registered;
	uint8_t flags;
};

server_cb是sever_fd IO到来时候的处理回调函数。当客户端连接时触发

static void server_cb(struct uloop_fd *fd, unsigned int events)
{
	bool next;

	do {
		next = get_next_connection(fd->fd);
	} while (next);
}

static struct uloop_fd server_fd = {
	.cb = server_cb,
};

get_next_connection() 建立一个新的ubus_client 维护一个对端,向client发送一个HELLO MSG,并开始监控这个远端client的写操作。 client 触发时的回调函数是client_cb

一个client 维护一个对端
struct ubus_client {
	struct ubus_id id;
	struct uloop_fd sock;
	struct blob_buf b;

	uid_t uid;
	gid_t gid;
	char *user;
	char *group;

	struct list_head objects;

	struct list_head tx_queue;
	unsigned int txq_ofs;
	unsigned int txq_len;

	struct ubus_msg_buf *pending_msg;
	struct ubus_msg_buf *retmsg;
	int pending_msg_offset;
	int pending_msg_fd;
	struct {
		struct ubus_msghdr hdr;
		struct blob_attr data;
	} hdrbuf;
};

static bool get_next_connection(int fd)
{
	struct ubus_client *cl;
	int client_fd;

	client_fd = accept(fd, NULL, 0);
	if (client_fd < 0) {
		switch (errno) {
		case ECONNABORTED:
		case EINTR:
			return true;
		default:
			return false;
		}
	}

	cl = ubusd_proto_new_client(client_fd, client_cb);
	if (cl)
		uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
	else
		close(client_fd);

	return true;
}

struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb)
{
	struct ubus_client *cl;

	cl = calloc(1, sizeof(*cl));
	if (!cl)
		return NULL;

	if (ubusd_acl_init_client(cl, fd))
		goto free;

	INIT_LIST_HEAD(&cl->objects);
	INIT_LIST_HEAD(&cl->tx_queue);
	cl->sock.fd = fd;
	cl->sock.cb = cb;
	cl->pending_msg_fd = -1;

	if (!ubus_alloc_id(&clients, &cl->id, 0))
		goto free;
	穿件ret
	if (ubusd_proto_init_retmsg(cl))
		goto free;

	if (!ubusd_send_hello(cl))
		goto delete;

	return cl;

delete:
	ubus_free_id(&clients, &cl->id);
free:
	free(cl);
	return NULL;
}

static void client_cb(struct uloop_fd *sock, unsigned int events)
{
	struct ubus_client *cl = container_of(sock, struct ubus_client, sock);
	uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
	struct msghdr msghdr = { 0 };
	struct ubus_msg_buf *ub;
	struct ubus_msg_buf_list *ubl, *ubl2;
	static struct iovec iov;
	struct cmsghdr *cmsg;
	int *pfd;

	msghdr.msg_iov = &iov,
	msghdr.msg_iovlen = 1,
	msghdr.msg_control = fd_buf;
	msghdr.msg_controllen = sizeof(fd_buf);

	cmsg = CMSG_FIRSTHDR(&msghdr);
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_len = CMSG_LEN(sizeof(int));

	pfd = (int *) CMSG_DATA(cmsg);
	msghdr.msg_controllen = cmsg->cmsg_len;

	/* first try to tx more pending data */
	list_for_each_entry_safe(ubl, ubl2, &cl->tx_queue, list) {
		ssize_t written;

		ub = ubl->msg;
		written = ubus_msg_writev(sock->fd, ub, cl->txq_ofs);
		if (written < 0) {
			switch(errno) {
			case EINTR:
			case EAGAIN:
				break;
			default:
				goto disconnect;
			}
			break;
		}

		cl->txq_ofs += written;
		cl->txq_len -= written;
		if (cl->txq_ofs < ub->len + sizeof(ub->hdr))
			break;

		ubus_msg_list_free(ubl);
	}

	/* prevent further ULOOP_WRITE events if we don't have data
	 * to send anymore */
	if (list_empty(&cl->tx_queue) && (events & ULOOP_WRITE))
		uloop_fd_add(sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);

send_msg的结构
iov[0]  ubus_msghdr
iov[1] struct blob_attr
retry:
	刚收到数据时,一定执行这段此时offset为0
	if (!sock->eof && cl->pending_msg_offset < (int) sizeof(cl->hdrbuf)) {
		int offset = cl->pending_msg_offset;
		int bytes;

		*pfd = -1;
		hdrbuf位置接收数据
		iov.iov_base = ((char *) &cl->hdrbuf) + offset;
		iov.iov_len = sizeof(cl->hdrbuf) - offset;
		fd_buf接收文件描述符
		if (cl->pending_msg_fd < 0) {
			msghdr.msg_control = fd_buf;
			msghdr.msg_controllen = cmsg->cmsg_len;
		} else {
			msghdr.msg_control = NULL;
			msghdr.msg_controllen = 0;
		}

		bytes = recvmsg(sock->fd, &msghdr, 0);
		if (bytes < 0)
			goto out;
		收到了fd,此fd 就是等待消息的fd pending_msg_fd
		if (*pfd >= 0)
			cl->pending_msg_fd = *pfd;

		cl->pending_msg_offset += bytes;
		收到的数据小于基本的接收结构时 退出
		if (cl->pending_msg_offset < (int) sizeof(cl->hdrbuf))
			goto out;
		收到的数据可以进行解释
		收到的数据data中不能解释为blob_attr时,退出
		if (blob_raw_len(&cl->hdrbuf.data) < sizeof(struct blob_attr))
			goto disconnect;
		收到数据过大 退出
		if (blob_pad_len(&cl->hdrbuf.data) > UBUS_MAX_MSGLEN)
			goto disconnect;
		新建一个ubus_msg
		cl->pending_msg = ubus_msg_new(NULL, blob_raw_len(&cl->hdrbuf.data), false);
		if (!cl->pending_msg)
			goto disconnect;

		cl->hdrbuf.hdr.seq = be16_to_cpu(cl->hdrbuf.hdr.seq);
		cl->hdrbuf.hdr.peer = be32_to_cpu(cl->hdrbuf.hdr.peer);
		将接受到的数据复制到pending_msg中
		memcpy(&cl->pending_msg->hdr, &cl->hdrbuf.hdr, sizeof(cl->hdrbuf.hdr));
		memcpy(cl->pending_msg->data, &cl->hdrbuf.data, sizeof(cl->hdrbuf.data));
	}
	pending_msg存在
	ub = cl->pending_msg;
	if (ub) {
		offset 是blob_attr 的总长度,当读到不是完整的blob_attr时offset小于blob_attr总长度
		int offset = cl->pending_msg_offset - sizeof(ub->hdr);
		len是blob_attr data的长度 len 是大于等于0int len = blob_raw_len(ub->data) - offset;
		int bytes = 0;

		if (len > 0) {
			若读取的是不完整的blob_attr时,再继续读取
			bytes = read(sock->fd, (char *) ub->data + offset, len);
			if (bytes <= 0)
				goto out;
		}

		if (bytes < len) {
			cl->pending_msg_offset += bytes;
			goto out;
		}

		/* accept message */
		保存传递过来的另一端fd
		ub->fd = cl->pending_msg_fd;
		cl->pending_msg_fd = -1;
		cl->pending_msg_offset = 0;
		cl->pending_msg = NULL;
		ubusd_monitor_message(cl, ub, false);
		ubusd_proto_receive_message(cl, ub);
		goto retry;
	}

out:
	if (!sock->eof || !list_empty(&cl->tx_queue))
		return;

disconnect:
	handle_client_disconnect(cl);
}

对收到message进行处理
void ubusd_proto_receive_message(struct ubus_client *cl, struct ubus_msg_buf *ub)
{
	ubus_cmd_cb cb = NULL;
	int ret;
	struct ubus_msg_buf *retmsg = cl->retmsg;
	int *retmsg_data = blob_data(blob_data(retmsg->data));

	retmsg->hdr.seq = ub->hdr.seq;
	retmsg->hdr.peer = ub->hdr.peer;

	if (ub->hdr.type < __UBUS_MSG_LAST)
		cb = handlers[ub->hdr.type];

	if (ub->hdr.type != UBUS_MSG_STATUS && ub->hdr.type != UBUS_MSG_INVOKE)
		ubus_msg_close_fd(ub);

	/* Note: no callback should free the `ub` buffer
	         that's always done right after the callback finishes */
	if (cb)
		ret = cb(cl, ub, ubus_parse_msg(ub->data, blob_raw_len(ub->data)));
	else
		ret = UBUS_STATUS_INVALID_COMMAND;

	ubus_msg_free(ub);

	if (ret == -1)
		return;

	*retmsg_data = htonl(ret);
	ubus_msg_send(cl, retmsg);
}

对主要申请接口的响应

static const ubus_cmd_cb handlers[__UBUS_MSG_LAST] = {
	[UBUS_MSG_PING] = ubusd_send_pong,
	[UBUS_MSG_ADD_OBJECT] = ubusd_handle_add_object,
	[UBUS_MSG_REMOVE_OBJECT] = ubusd_handle_remove_object,
	[UBUS_MSG_LOOKUP] = ubusd_handle_lookup,
	[UBUS_MSG_INVOKE] = ubusd_handle_invoke,
	[UBUS_MSG_STATUS] = ubusd_handle_response,
	[UBUS_MSG_DATA] = ubusd_handle_response,
	[UBUS_MSG_SUBSCRIBE] = ubusd_handle_add_watch,
	[UBUS_MSG_UNSUBSCRIBE] = ubusd_handle_remove_watch,
	[UBUS_MSG_NOTIFY] = ubusd_handle_notify,
};

ubusd 中用的buffer结构

struct ubus_id {
	struct avl_node avl;
	uint32_t id;
};

struct ubus_msg_buf {
	uint32_t refcount; /* ~0: uses external data buffer */
	struct ubus_msghdr hdr;
	struct blob_attr *data;
	int fd;
	int len;
};

struct ubus_msghdr {
	uint8_t version;
	uint8_t type;
	uint16_t seq;
	uint32_t peer;
} __packetdata;

ubus_msghdr_buf
在这里插入图片描述

server 和client

流程

int main(int argc, char **argv)
{
	const char *ubus_socket = NULL;
	int ch;

	while ((ch = getopt(argc, argv, "cs:")) != -1) {
		switch (ch) {
		case 's':
			ubus_socket = optarg;
			break;
		default:
			break;
		}
	}

	uloop_init();

	ctx = ubus_connect(ubus_socket);
	if (!ctx) {
		fprintf(stderr, "Failed to connect to ubus\n");
		return -1;
	}

	ubus_add_uloop(ctx);

	client_main();

	ubus_free(ctx);
	uloop_done();

	return 0;
}

初始化

ubus_connect() 创建struct ubus_context 并初始化,向ubusd建立连接,获得ctx->sock, 然后接收到HELLO MSG, 清空avl tree。
ubus_add_uloop(ctx) 将ctx->sock 加入到监听器中。

struct ubus_context {
	struct list_head requests;
	平衡树对象
	struct avl_tree objects;
	struct list_head pending;

	struct uloop_fd sock;
	struct uloop_timeout pending_timer;

	uint32_t local_id;
	uint16_t request_seq;
	bool cancel_poll;
	int stack_depth;

	void (*connection_lost)(struct ubus_context *ctx);
	void (*monitor_cb)(struct ubus_context *ctx, uint32_t seq, struct blob_attr *data);

	struct ubus_msghdr_buf msgbuf;
	uint32_t msgbuf_data_len;
	int msgbuf_reduction_counter;
};

struct ubus_context *ubus_connect(const char *path)
{
	struct ubus_context *ctx;

	ctx = calloc(1, sizeof(*ctx));
	if (!ctx)
		return NULL;

	if (ubus_connect_ctx(ctx, path)) {
		free(ctx);
		ctx = NULL;
	}

	return ctx;
}

int ubus_connect_ctx(struct ubus_context *ctx, const char *path)
{
	uloop_init();
	memset(ctx, 0, sizeof(*ctx));

	ctx->sock.fd = -1;
	处理接收数据的回调函数
	ctx->sock.cb = ubus_handle_data;
	ctx->connection_lost = ubus_default_connection_lost;
	ctx->pending_timer.cb = ubus_process_pending_msg;

	ctx->msgbuf.data = calloc(1, UBUS_MSG_CHUNK_SIZE);
	if (!ctx->msgbuf.data)
		return -1;
	ctx->msgbuf_data_len = UBUS_MSG_CHUNK_SIZE;

	INIT_LIST_HEAD(&ctx->requests);
	INIT_LIST_HEAD(&ctx->pending);
	avl_init(&ctx->objects, ubus_cmp_id, false, NULL);
	if (ubus_reconnect(ctx, path)) {
		free(ctx->msgbuf.data);
		ctx->msgbuf.data = NULL;
		return -1;
	}

	return 0;
}
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.eof = false;
	ctx->sock.error = false;
	连接ubusd时触发server_cb
	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)) != (ssize_t) 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 | O_CLOEXEC);

	ubus_refresh_state(ctx);

out_free:
	free(buf);
out_close:
	if (ret)
		close(ctx->sock.fd);

	return ret;
}

struct ubus_request {
	struct list_head list;

	struct list_head pending;
	int status_code;
	bool status_msg;
	bool blocked;
	bool cancelled;
	bool notify;

	uint32_t peer;
	uint16_t seq;

	ubus_data_handler_t raw_data_cb;
	ubus_data_handler_t data_cb;
	ubus_fd_handler_t fd_cb;
	ubus_complete_handler_t complete_cb;

	int fd;

	struct ubus_context *ctx;
	void *priv;
};

添加ubus_object

struct ubus_object {
	struct avl_node avl;

	const char *name;
	uint32_t id;

	const char *path;
	struct ubus_object_type *type;

	ubus_state_handler_t subscribe_cb;
	bool has_subscribers;

	const struct ubus_method *methods;
	int n_methods;
};

struct ubus_request {
	struct list_head list;

	struct list_head pending;
	int status_code;
	bool status_msg;
	bool blocked;
	bool cancelled;
	bool notify;

	uint32_t peer;
	uint16_t seq;

	ubus_data_handler_t raw_data_cb;
	ubus_data_handler_t data_cb;
	ubus_fd_handler_t fd_cb;
	ubus_complete_handler_t complete_cb;

	int fd;

	struct ubus_context *ctx;
	void *priv;
};
static void client_main(void)
{
	static struct ubus_request req;
	uint32_t id;
	int ret;

	ret = ubus_add_object(ctx, &test_client_object);
	if (ret) {
		fprintf(stderr, "Failed to add_object object: %s\n", ubus_strerror(ret));
		return;
	}

	if (ubus_lookup_id(ctx, "test", &id)) {
		fprintf(stderr, "Failed to look up test object\n");
		return;
	}

	blob_buf_init(&b, 0);

	blobmsg_add_u32(&b, "id", test_client_object.id);
	ubus_invoke(ctx, id, "watch", b.head, NULL, 0, 3000);
	test_client_notify_cb(&notify_timer);

	blob_buf_init(&b, 0);
	blobmsg_add_string(&b, "msg", "blah");
	ubus_invoke_async(ctx, id, "hello", b.head, &req);
	req.fd_cb = test_client_fd_cb;
	req.complete_cb = test_client_complete_cb;
	ubus_complete_request_async(ctx, &req);

	uloop_timeout_set(&count_timer, 2000);

	uloop_run();
}
ubus_add_object()
struct ubus_request {
	struct list_head list;

	struct list_head pending;
	int status_code;
	bool status_msg;
	bool blocked;
	bool cancelled;
	bool notify;

	uint32_t peer;
	uint16_t seq;

	ubus_data_handler_t raw_data_cb;
	ubus_data_handler_t data_cb;
	ubus_fd_handler_t fd_cb;
	ubus_complete_handler_t complete_cb;

	int fd;

	struct ubus_context *ctx;
	void *priv;
};

int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj)
{
	用来处理返回数据
	struct ubus_request req;
	int ret;

	blob_buf_init(&b, 0);

	if (obj->name && obj->type) {
		blob_put_string(&b, UBUS_ATTR_OBJPATH, obj->name);

		if (obj->type->id)
			blob_put_int32(&b, UBUS_ATTR_OBJTYPE, obj->type->id);
		else if (!ubus_push_object_type(obj->type))
			return UBUS_STATUS_INVALID_ARGUMENT;
	}

	if (ubus_start_request(ctx, &req, b.head, UBUS_MSG_ADD_OBJECT, 0) < 0)
		return UBUS_STATUS_INVALID_ARGUMENT;

	req.raw_data_cb = ubus_add_object_cb;
	req.priv = obj;
	ret = ubus_complete_request(ctx, &req, 0);
	if (ret)
		return ret;

	if (!obj->id)
		return UBUS_STATUS_NO_DATA;

	return 0;
}

int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
				struct blob_attr *msg, int cmd, uint32_t peer)
{
	memset(req, 0, sizeof(*req));

	req->fd = -1;

	return __ubus_start_request(ctx, req, msg, cmd, peer);
}

int __hidden __ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
				struct blob_attr *msg, int cmd, uint32_t peer)
{

	if (msg && blob_pad_len(msg) > UBUS_MAX_MSGLEN)
		return -1;

	INIT_LIST_HEAD(&req->list);
	INIT_LIST_HEAD(&req->pending);
	req->ctx = ctx;
	req->peer = peer;
	req->seq = ++ctx->request_seq;

	return ubus_send_msg(ctx, req->seq, msg, cmd, peer, req->fd);
}

send_msg的结构
iov[0]  ubus_msghdr
iov[1] struct blob_attr
int __hidden ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
			   struct blob_attr *msg, int cmd, uint32_t peer, int fd)
{
	struct ubus_msghdr hdr;
	struct iovec iov[2] = {
		STATIC_IOV(hdr)
	};
	int ret;

	hdr.version = 0;
	hdr.type = cmd;
	hdr.seq = cpu_to_be16(seq);
	hdr.peer = cpu_to_be32(peer);

	if (!msg) {
		blob_buf_init(&b, 0);
		msg = b.head;
	}

	iov[1].iov_base = (char *) msg;
	iov[1].iov_len = blob_raw_len(msg);

	ret = writev_retry(ctx->sock.fd, iov, ARRAY_SIZE(iov), fd);
	if (ret < 0)
		ctx->sock.eof = true;

	if (fd >= 0)
		close(fd);

	return ret;
}

iov buffer中的数据可能不会一次就能发完,writev_retry 多次sendms直到把iovbuffer中的数据发完。
static int writev_retry(int fd, struct iovec *iov, int iov_len, int sock_fd)
{
	uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
	struct msghdr msghdr = { 0 };
	struct cmsghdr *cmsg;
	int len = 0;
	int *pfd;

	msghdr.msg_iov = iov,
	msghdr.msg_iovlen = iov_len,
	msghdr.msg_control = fd_buf;
	msghdr.msg_controllen = sizeof(fd_buf);

	cmsg = CMSG_FIRSTHDR(&msghdr);
	cmsg->cmsg_type = SCM_RIGHTS;
	cmsg->cmsg_level = SOL_SOCKET;
	cmsg->cmsg_len = CMSG_LEN(sizeof(int));

	pfd = (int *) CMSG_DATA(cmsg);
	msghdr.msg_controllen = cmsg->cmsg_len;

	do {
		ssize_t cur_len;
		附加信息就是sock_fd,传递这个文件描述符
		if (sock_fd < 0) {
			msghdr.msg_control = NULL;
			msghdr.msg_controllen = 0;
		} else {
			*pfd = sock_fd;
		}

		cur_len = sendmsg(fd, &msghdr, 0);
		if (cur_len < 0) {
			switch(errno) {
			case EAGAIN:
				wait_data(fd, true);
				break;
			case EINTR:
				break;
			default:
				return -1;
			}
			continue;
		}

		if (len > 0)
			sock_fd = -1;

		len += cur_len;
		判断是否将iov buffer中的数据发完
		while (cur_len >= (ssize_t) iov->iov_len) {
			cur_len -= iov->iov_len;
			iov_len--;
			iov++;
			正好发完时 从这里退出
			if (!iov_len)
				return len;
		}
		没发完继续发送
		iov->iov_base += cur_len;
		iov->iov_len -= cur_len;
		msghdr.msg_iov = iov;
		msghdr.msg_iovlen = iov_len;
	} while (1);

	/* Should never reach here */
	return -1;
}

接收数据处理

void __hidden ubus_handle_data(struct uloop_fd *u, unsigned int events)
{
	struct ubus_context *ctx = container_of(u, struct ubus_context, sock);
	int recv_fd = -1;

	while (get_next_msg(ctx, &recv_fd)) {
		ubus_process_msg(ctx, &ctx->msgbuf, recv_fd);
		if (uloop_cancelling() || ctx->cancel_poll)
			break;
	}

	if (u->eof)
		ctx->connection_lost(ctx);
}

void __hidden
ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd)
{
	switch(buf->hdr.type) {
	case UBUS_MSG_STATUS:
	case UBUS_MSG_DATA:
		ubus_process_req_msg(ctx, buf, fd);
		break;

	case UBUS_MSG_INVOKE:
	case UBUS_MSG_UNSUBSCRIBE:
	case UBUS_MSG_NOTIFY:
		if (ctx->stack_depth) {
			ubus_queue_msg(ctx, buf);
			break;
		}

		ubus_process_obj_msg(ctx, buf, fd);
		break;
	case UBUS_MSG_MONITOR:
		if (ctx->monitor_cb)
			ctx->monitor_cb(ctx, buf->hdr.seq, buf->data);
		break;
	}
}

返回数据相关结构

struct ubus_request_data {
	uint32_t object;
	uint32_t peer;
	uint16_t seq;

	struct ubus_acl_key acl;

	/* internal use */
	bool deferred;
	int fd;
	int req_fd; /* fd received from the initial request */
};

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ubus数据具有多层嵌套的BLOBMSG_TYPE_TABLE或BLOBMSG_TYPE_ARRAY类型时,可以使用递归的方式进行解析。下面是一个示例代码,演示了如何解析多层嵌套的ubus数据: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libubox/blobmsg_json.h> void parse_blobmsg_table(const struct blob_attr *attr); void parse_blobmsg_array(const struct blob_attr *attr) { int rem; struct blob_attr *tb[BLOBMSG_TYPE_MAX + 1]; struct blob_attr *cur; blobmsg_for_each_attr(cur, attr, rem) { if (blobmsg_type(cur) == BLOBMSG_TYPE_TABLE) { parse_blobmsg_table(cur); } else if (blobmsg_type(cur) == BLOBMSG_TYPE_ARRAY) { parse_blobmsg_array(cur); } else { fprintf(stderr, "Unexpected blobmsg type\n"); } } } void parse_blobmsg_table(const struct blob_attr *attr) { int rem; struct blob_attr *tb[BLOBMSG_TYPE_MAX + 1]; struct blob_attr *cur; blobmsg_parse(tb, BLOBMSG_TYPE_MAX, blobmsg_data(attr), blobmsg_data_len(attr)); if (!tb[0]) { fprintf(stderr, "Failed to parse blobmsg table\n"); return; } blobmsg_for_each_attr(cur, tb[0], rem) { if (blobmsg_type(cur) == BLOBMSG_TYPE_TABLE) { parse_blobmsg_table(cur); } else if (blobmsg_type(cur) == BLOBMSG_TYPE_ARRAY) { parse_blobmsg_array(cur); } else { // Handle individual values // You can access the value using blobmsg_get_type() and blobmsg_get_* functions const char *key = blobmsg_name(cur); int val = blobmsg_get_u32(cur); printf("Key: %s, Value: %d\n", key, val); } } } int main() { // Example ubus data in JSON format const char *json_data = "{\"table\":{\"nested_table\":{\"array\":[1,2,3]},\"value\":123}}"; struct blob_attr *attr; struct blob_buf buf; blob_buf_init(&buf, 0); if (blobmsg_add_json_from_string(&buf, json_data) != 0) { fprintf(stderr, "Failed to parse JSON data\n"); return 1; } attr = buf.head; if (!attr) { fprintf(stderr, "Empty blobmsg data\n"); return 1; } parse_blobmsg_table(attr); return 0; } ``` 在这个示例代码中,我们使用了libubox库中的函数来解析ubus数据。首先,我们将JSON格式的ubus数据转换为blobmsg格式,然后使用parse_blobmsg_table函数进行解析。在解析过程中,如果遇到嵌套的BLOBMSG_TYPE_TABLE类型或BLOBMSG_TYPE_ARRAY类型,就会递归调用相应的解析函数。 在parse_blobmsg_table函数中,我们使用了blobmsg_type和blobmsg_for_each_attr函数来遍历解析后的数据。对于嵌套的BLOBMSG_TYPE_TABLE和BLOBMSG_TYPE_ARRAY类型,我们会分别调用parse_blobmsg_table和parse_blobmsg_array函数进行解析。对于其他类型,我们可以使用blobmsg_get_*函数来获取具体的值。 请注意,这只是一个简单的示例代码,实际的解析过程可能更加复杂,需要根据具体的ubus数据结构和需求进行适当的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值