简介
ubus是新openwrt引入的一个消息总线,主要作用是实现不同应用程序之间的信息交互。
ubus启动后会在后台运行ubusd进程,该进程监听一个unix套接字用于与其他应用程序通信。其他应用程序可基于libubox提供的接口(或自己实现)与其通信。
使用ubus的方式主要有:1、向其注册消息或控制接口。2、向其调用其他应用程序的消息或控制接口。3、向其注册监听关心的事件。4、向其发送事件消息。
ubus命令使用说明
ubus命令用于控制调试相关ubus接口,主要命令说明如下:
- list [<path>] List objects
- call <path> <method> [<message>] Call an object method
- listen [<path>...] Listen for events
- send <type> [<message>] Send an event
- wait_for <object> [<object>...] Wait for multiple objects to appear on ubus
ubus list [-v] 该命令用于显示当前ubus中注册的接口,其中-v参数用以显示各个接口的详细信息。示例如下:
ubus list -v 'dhcp' @26b45f5d "ipv4leases":{} "ipv6leases":{} 'hostapd.wlan0' @5e03d420 "get_clients":{} "del_client":{"addr":"String","reason":"Integer","deauth":"Boolean","ban_time":"Integer"}
ubus call 该命令用于调用ubus中当前注册的接口。示例如下:
ubus call dhcp ipv6leases { "device": { "br-lan": { "leases": [ { "duid": "0001000119660ee***4e543***3c70", "iaid": 3***72***5, "hostname": "*******-PC", "assigned": 3900, "length": 128, "ipv6": [ "fd23:a6ed:f19b::f3c" ], "valid": -38000 } ] } } }
ubus listen 用于监听ubus相关事件,如果不指定事件名则监听所有事件。(支持通配符*)
ubus send 用于发送事件
ubus wait_for 用于等待指定项的注册到ubus中。
libubus开发说明
libubus与需要与libubox配合使用,先贴出调用libubus的实例代码。
ubus.h
#ifndef UBUS_H_ #define UBUS_H_ #include <libubox/blob.h> int ubus_send(const char *type, struct blob_attr *data); int ubus_call(const char *path, const char *method, struct blob_attr *data, struct blob_attr **ret); int ubus_init(void); void ubus_destory(); #endif
ubus.c
#include <stdio.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <libubus.h> #include <libubox/uloop.h> #include <libubox/blobmsg_json.h> #include <arpa/inet.h> #include "ubus.h" #include "test.h" #include "debug.h" #include "pubinfo.h" struct ubus_context *ubus_ctx = NULL; #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) enum {GET_TYPE_FLOW, GET_TYPE_SPEED}; #define _unused __attribute__((unused)) #define _packed __attribute__((packed)) static struct blob_buf b; /********************************************************************** * pub policy *********************************************************************/ enum { UBUS_test_PUB_TOPIC, UBUS_test_PUB_MSG, __UBUS_test_PUB_MAX }; static const struct blobmsg_policy test_pub_policy[] ={ [UBUS_test_PUB_TOPIC] = { .name = "topic", .type = BLOBMSG_TYPE_STRING }, [UBUS_test_PUB_MSG] = { .name = "msg", .type = BLOBMSG_TYPE_TABLE }, }; /********************************************************************** * Stats policy *********************************************************************/ enum { UBUS_STATS_OBJS, __UBUS_STATS_MAX }; static const struct blobmsg_policy stats_pub_policy[] ={ [UBUS_STATS_OBJS] = { .name = "obj", .type = BLOBMSG_TYPE_ARRAY }, }; /********************************************************************** * sub policy *********************************************************************/ enum { UBUS_test_SUB_TOPICS, __UBUS_test_SUB_MAX }; static const struct blobmsg_policy test_sub_policy[] ={ [UBUS_test_SUB_TOPICS] = { .name = "topics", .type = BLOBMSG_TYPE_ARRAY }, }; /********************************************************************** * subscribe method: subscribe a list of topics *********************************************************************/ static int ubus_test_sub(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { unsigned ret=0; struct blob_attr *tb[__UBUS_test_SUB_MAX]; blobmsg_parse(test_sub_policy, __UBUS_test_SUB_MAX, tb, blob_data(msg), blob_len(msg)); if (!tb[UBUS_test_SUB_TOPICS]){ debug(MSG_ERROR, "ubus test sub: no arguments!"); goto out; } update_test_topic_list(tb[UBUS_test_SUB_TOPICS]); ret=1; out: blob_buf_init(&b, 0); blobmsg_add_u8(&b, "result", ret); ubus_send_reply(ctx, req, b.head); return 0; } /********************************************************************** * publish method: publish messages *********************************************************************/ static int ubus_test_pub(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { int ret=0; struct blob_attr *tb[__UBUS_test_PUB_MAX]; char *message="", *topic; blobmsg_parse(test_pub_policy, __UBUS_test_PUB_MAX, tb, blob_data(msg), blob_len(msg)); if (!tb[UBUS_test_PUB_TOPIC]) { goto out; } topic=blobmsg_get_string(tb[UBUS_test_PUB_TOPIC]); if (tb[UBUS_test_PUB_MSG]!=NULL) { message=(char*)blobmsg_data(tb[UBUS_test_PUB_MSG]); } test_pub_msg(topic, message); debug(MSG_INFO, "PUB: topic=%s msg=%s\n",topic,message); ret=1; out: blob_buf_init(&b, 0); blobmsg_add_u8(&b, "result", ret); ubus_send_reply(ctx, req, b.head); return 0; } /********************************************************************** * publish method: simple publish messages *********************************************************************/ static int ubus_test_spub(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { int ret=0; struct blob_attr *tb[__UBUS_test_PUB_MAX]; char *message="", *cmd; blobmsg_parse(test_pub_policy, __UBUS_test_PUB_MAX, tb, blob_data(msg), blob_len(msg)); if (!tb[UBUS_test_PUB_TOPIC]){ debug(MSG_ERROR, "ubus call spub without topic"); goto out; } cmd=blobmsg_get_string(tb[UBUS_test_PUB_TOPIC]); if (tb[UBUS_test_PUB_MSG]!=NULL){ message=blobmsg_format_json(tb[UBUS_test_PUB_MSG], true); } simple_pub_msg(cmd, message, 1); ret=1; out: blob_buf_init(&b, 0); blobmsg_add_u8(&b, "result", ret); ubus_send_reply(ctx, req, b.head); return 0; } /********************************************************************** * list method: list current subscribe topic *********************************************************************/ static int ubus_test_list(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { get_topic_list(&b); ubus_send_reply(ctx, req, b.head); return 0; } /********************************************************************** * ubus method: ubus_pub_stats *********************************************************************/ static int ubus_pub_stats(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { int ret = 0; struct blob_attr *tb[__UBUS_STATS_MAX]; blobmsg_parse(stats_pub_policy, __UBUS_STATS_MAX, tb, blob_data(msg), blob_len(msg)); if (tb[UBUS_STATS_OBJS]) { pub_info(tb[UBUS_STATS_OBJS]); ret = 1; } blob_buf_init(&b, 0); blobmsg_add_u8(&b, "result", ret); ubus_send_reply(ctx, req, b.head); return 0; } /********************************************************************** * list method: list current subscribe topic *********************************************************************/ static int ubus_test_test(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { int status; get_topic_list(&b); debug(MSG_DEBUG, "==>begin wait status"); wait(&status); debug(MSG_DEBUG, "==>after wait status:%d", status); ubus_send_reply(ctx, req, b.head); return 0; } /********************************************************************** * test method *********************************************************************/ static const struct ubus_method test_methods[] = { UBUS_METHOD("pub",ubus_test_pub,test_pub_policy), UBUS_METHOD("spub",ubus_test_spub,test_pub_policy), UBUS_METHOD("sub",ubus_test_sub,test_sub_policy), UBUS_METHOD("pubstats",ubus_pub_stats, stats_pub_policy), UBUS_METHOD_NOARG("lsub",ubus_test_list), UBUS_METHOD_NOARG("test",ubus_test_test), }; /********************************************************************** * test object *********************************************************************/ static struct ubus_object_type test_object_type = UBUS_OBJECT_TYPE("test", test_methods); static struct ubus_object test_object = { .name = "test", .type = &test_object_type, .methods = test_methods, .n_methods = ARRAY_SIZE(test_methods), }; static void ubus_connect_handler(struct ubus_context *ctx) { ubus_ctx = ctx; debug(MSG_DEBUG, "ubus now connected."); ubus_add_uloop(ctx); ubus_add_object(ctx, &test_object); return; } static struct ubus_auto_conn conn; static void receive_ubus_data(struct ubus_request *req, int type, struct blob_attr *msg) { struct blob_attr **ret = (struct blob_attr **)req->priv; *ret = blob_memdup(msg); } int ubus_send(const char *type, struct blob_attr *data) { if (!ubus_ctx || !type || !data) { return -1; } return ubus_send_event(ubus_ctx, type, data); } int ubus_call(const char *path, const char *method, struct blob_attr *data, struct blob_attr **ret) { uint32_t id; int _ret; if (ubus_ctx == NULL) { return -1; } _ret = ubus_lookup_id(ubus_ctx, path, &id); if (_ret) { debug(MSG_ERROR, "lookup stats id error!"); return -1; } return ubus_invoke(ubus_ctx, id, method, data, receive_ubus_data, ret, 1000); } int ubus_init(void) { conn.cb = ubus_connect_handler; ubus_auto_connect(&conn); return 0; } void ubus_destory() { /* ubus_remove_object(ubus, &main_object); ubus_free(ubus); */ }