ubus應用-第二篇ubus代碼應用


本文寫作目的是方便以后查詢使用,以實用為主。前期完全不會ubus使用的時候看了一些文章,確實是很詳盡的,但是我很難一下子進行應用(本人水平有限),在經過一些時間的使用之后逐漸了解其中的使用方法,希望這篇文章能夠總結的很容易懂,能夠幫到最開始接觸ubus的人。

關於ubus的基本使用機制可以參看我之前的一篇文章(https://www.cnblogs.com/y-c-y/p/12187422.html),本篇更注重於代碼使用。

ubus server

在本文中假設您已經對object等ubus基本概念已經有所了解了(如果沒有可以參見我之前的文章),本次代碼講解將圍繞以下兩個表格進行講解。

作為ubus server進程實現以下兩個表格的功能:

根據以上兩個表格,可以得出以下這些命令是本ubus server 進程支持的:

ubus call YCY my_ubus_method_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus call YCY my_ubus_method_2 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus call YCY my_ubus_method_3 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus call CCYY my_ubus_method_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus call CCYY my_ubus_method_2 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus call CCYY my_ubus_method_3 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus send my_notify '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus send my_notify_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'

PS:
1.ubus call YCY my_ubus_method_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus :指的是ubus命令,所有代碼中實現的ubus命令都可以通過ubus -v list查看到,或者是ubus list -v 。
call:指的是call調用,ubus調用方法還有另外的send。
YCY:指的是ubus object
my_ubus_method_1:指的是ubus method
'{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.22.1.2"}':指的是ubus call method需要使用的參數,其實如果對應的method要用到這些是需要傳送的,如果有些method不需要參數(例如代碼中的method2和method3)就算傳了參數也沒有關系,ubus不會判定語法出錯,只不過是對應method並不會解析這些參數而已。

2.ubus send my_notify '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'
ubus :指的是ubus命令,所有代碼中實現的ubus命令都可以通過ubus -v list查看到,或者是ubus list -v 。
send :指的是send調用
'{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.22.1.2"}':指的是ubus send需要使用的參數,具體同上。

3.其實從表格上也可以看出對於ubus call和ubus send兩種命令的使用差別,ubus call是需要有明確調用對象的,類似於單播命令,而ubus send是沒有明確調用對象的,是對所有的ubus進程發送notify消息,類似於廣播命令;而所有接收到這個notify的ubus client進程,如果注冊了這個notify,ubus client進程就會觸發回調函數處理這個notify,ubus client進程沒有注冊這個notify的就無視它。

ubus server代碼

注意事項(我想還是把注意事項寫在代碼前面為好,正確使用代碼比使用代碼更為重要,可以避免很多不必要的錯誤):

1.同一個ubus進程可以注冊多個ubus object,例如 ubus call CCYY my_ubus_method_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.22.1.2"}' 。

2.policy注意不能是NULL。


#define MY_UBUS_OBJECT_NAME	"YCY"
#define MY_UBUS_OBJECT_NAME_1	"CCYY"

#define MY_UBUS_NOTIFY_EVENT    "my_notify"
#define MY_UBUS_NOTIFY_EVENT_1  "my_notify_1"

#define MY_UBUS_METHOD_1 "my_ubus_method_1"
#define MY_UBUS_METHOD_2 "my_ubus_method_2"
#define MY_UBUS_METHOD_3 "my_ubus_method_3"

#define MY_UBUS_PARAM_NAME_1 "mac_addr"
#define MY_UBUS_PARAM_NAME_2 "ipv4_addr"

typedef (void *)my_ubus_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg);

/* global variables */
struct ubus_context *g_ubus_ctx;
struct blob_buf g_ubus_buf;
struct ubud_event_handler g_ubus_notify;
struct ubud_event_handler g_ubus_notify_1;

/* method function declare */
int my_ubus_method_1(struct ubus_context *ctx, struct ubus_object *obj,
									struct ubus_request_data *req, const char *method, 
									struct blob_attr *msg);
int my_ubus_method_2(struct ubus_context *ctx, struct ubus_object *obj,
									struct ubus_request_data *req, const char *method, 
									struct blob_attr *msg);
int my_ubus_method_3(struct ubus_context *ctx, struct ubus_object *obj,
					struct ubus_request_data *req, const char *method, 
					struct blob_attr *msg);
void my_wifi_notify_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, 
	                                const char *type, struct blob_attr *msg);

/* policy */
enum
{
    PARAM_MAC_ADDR,
	PARAM_IP4_ADDR,
	PARAM_MAX
}

static const struct blobmsg_policy my_ubus_policy[PARAM_MAX] = 
{
    [PARAM_MAC_ADDR] = {.name = MY_UBUS_PARAM_NAME_1, .type = BLOBMSG_TYPE_STRING},
    [PARAM_IP4_ADDR] = {.name = MY_UBUS_PARAM_NAME_2, .type = BLOBMSG_TYPE_STRING},
};

static const struct ubus_method g_ubus_methods[] = 
{
	UBUS_METHOD(MY_UBUS_METHOD_1, my_ubus_method_1, my_ubus_policy),//注意這里的policy絕對不能是NULL,程序運行會出錯
	UBUS_METHOD(MY_UBUS_METHOD_2, my_ubus_method_2, my_ubus_policy),
	UBUS_METHOD(MY_UBUS_METHOD_3, my_ubus_method_3, my_ubus_policy),
};

static struct ubus_object_type g_ubus_type = UBUS_OBJECT_TYPE(MY_UBUS_OBJECT_NAME, g_ubus_methods);

struct ubus_object g_ubus_object = 
{
	.name = MY_UBUS_OBJECT_NAME,
	.type = &g_ubus_type,
	.methods = g_ubus_methods,
	.n_methods = ARRAY_SIZE(g_ubus_methods)
};

static struct ubus_object_type g_ubus_type_1 = UBUS_OBJECT_TYPE(MY_UBUS_OBJECT_NAME_1, g_ubus_methods);/* g_ubus_methods 可以是其他的,這里是為了去掉重復代碼簡便使用 */

struct ubus_object g_ubus_object_1 = 
{
	.name = MY_UBUS_OBJECT_NAME_1,
	.type = &g_ubus_type_1,
         /* g_ubus_methods 可以是其他的,這里是為了去掉重復代碼簡便使用 */
	.methods = g_ubus_methods,
	.n_methods = ARRAY_SIZE(g_ubus_methods)
};

int my_ubus_add_object()
{
        int ret = 0;
	
	ret = ubus_add_object(g_ubus_ctx, &g_ubus_object);
	if (ret != 0)
	{
		printf("failed to add object to ubus\n");
		return -1;
	}

	ret = ubus_add_object(g_ubus_ctx, &g_ubus_object_1);
	if (ret != 0)
	{
		printf("failed to add object to ubus\n");
		return -1;
	}
	return 0;
}

int my_ubus_register_event(struct ubus_context ctx, struct ubud_event_handler *notify, my_ubus_event_handler fun, char *notify_event)
{
        int ret = 0;
	
	memset(notify, 0, sizeof(struct ubus_event_handler));
	notify->cb = fun;
	ret = ubus_register_event_handler(ctx, notify, notify_event);
	if (ret != 0)
	{
		printf("Failed to register wifi notify event to ubus server %s\n", ubus_strerror(ret));
		return -1;
	}
	
	return 0;
}

int my_ubus_register_event_all()
{
        int ret = 0;
	
	ret = my_ubus_register_event(g_ubus_ctx, &g_ubus_notify, my_wifi_notify_handler, MY_UBUS_NOTIFY_EVENT);
	                                                          /* your own handler function */
        ret = my_ubus_register_event(g_ubus_ctx, &g_ubus_notify_1, my_wifi_notify_handler, MY_UBUS_NOTIFY_EVENT_1);

	return ret;
}

int my_ubus_start(void)
{
	int ret = 0;
	int i = 0;

	printf("wifison ubus start\n");
	uloop_init();

	g_ubus_ctx = ubus_connect(NULL);
	if (g_ubus_ctx == NULL)
	{
		printf("failed to connect to ubus\n");
		return -1;
	}

	ubus_add_uloop(g_ubus_ctx);

        /* ubus add objects */
        ret = my_ubus_add_object();
	if (ret != 0)
	{
		printf("failed to add object to ubus\n");
		return -1;
	}
	
	/* ubus register events */
	my_ubus_register_event_all();
	if (ret != 0)
	{
		printf("failed to register event to ubus\n");
		return -1;
	}

	uloop_run();//loop

	/* unregister ubus event */
	ret = ubus_unregister_event_handler(g_ubus_ctx, &g_ubus_notify);
	if(ret != 0)
	{
		printf("Failed to unregister notify event to ubus server %s\n", ubus_strerror(ret));
		return -1;
	}

	/* free resource */
	ubus_free(g_ubus_ctx);
	uloop_done();
	printf("return out of uloop_run\n");

	return 0;
}

int main()
{
    my_ubus_start();
    return 0;
}

void my_wifi_notify_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *type, struct blob_attr *msg)
{
	struct blob_attr *tb[PARAM_MAX] = {NULL};
	char mac_addr[32] = {0};
	char ipv4_addr[32] = {0};

	if (!msg)
	{
		printf(" input msg is NULL\n");
		return;
	}

	/* 這個函數按照my_ubus_policy規則解析收到的ubus參數,然后保存在tb臨時變量中 */
	blobmsg_parse(my_ubus_policy, PARAM_MAX, tb, blob_data(msg), blob_len(msg));

	//macaddr
	if( NULL != tb[PARAM_MAC_ADDR] )
	{
		strcpy(mac_addr, blobmsg_get_string(tb[PARAM_IP4_ADDR]));
	}

	//ipv4_addr
	if( NULL != tb[PARAM_IP4_ADDR] )
	{
		strcpy(ipv4_addr, blobmsg_get_string(tb[PARAM_IP4_ADDR]));
	}

	/* TO DO */
	
}

static int my_ubus_method_1(struct ubus_context *ctx, struct ubus_object *obj,
									struct ubus_request_data *req, const char *method, 
									struct blob_attr *msg)
{
	json_object *this_wifison_all_info = NULL;
	json_object *this_cap_sys_info = NULL;
	struct blob_attr *tb[PARAM_MAX] = {NULL};
	char mac_addr[32] = {0};
	char ipv4_addr[32] = {0};

	if (!msg)
	{
		printf(" input msg is NULL\n");
		return;
	}

	/* 這個函數按照my_ubus_policy規則解析收到的ubus參數,然后保存在tb臨時變量中 */
	blobmsg_parse(my_ubus_policy, PARAM_MAX, tb, blob_data(msg), blob_len(msg));

	//macaddr
	if( NULL != tb[PARAM_MAC_ADDR] )
	{
		strcpy(mac_addr, blobmsg_get_string(tb[PARAM_IP4_ADDR]));
	}

	//ipv4_addr
	if( NULL != tb[PARAM_IP4_ADDR] )
	{
		strcpy(ipv4_addr, blobmsg_get_string(tb[PARAM_IP4_ADDR]));
	}
	
	this_wifison_all_info = json_object_new_object();	
	this_cap_sys_info = json_object_new_object();
	json_object_object_add(this_wifison_all_info, "sys_info", this_cap_sys_info);
	json_object_object_add(this_cap_sys_info, "other_mac", json_object_new_string(g_wifison_info.cap_info.sys_info.sn));
	json_object_object_add(this_cap_sys_info, "other_ipv4", json_object_new_string(g_wifison_info.cap_info.sys_info.model));
	
	blob_buf_init(&g_ubus_buf, 0);
	blobmsg_add_object(&g_ubus_buf, this_wifison_all_info);
	ubus_send_reply(ctx, req, g_ubus_buf.head); 

	json_object_put(this_cap_sys_info);	
	json_object_put(this_wifison_all_info);
	
	return 0;
}

static int my_ubus_method_2(struct ubus_context *ctx, struct ubus_object *obj,
				struct ubus_request_data *req, const char *method, 
				struct blob_attr *msg)
{
    /* TO DO */
	
	return 0;
}
		
static int my_ubus_method_3(struct ubus_context *ctx, struct ubus_object *obj,
				struct ubus_request_data *req, const char *method, 
				struct blob_attr *msg)
{
	/* TO DO */
	
	return 0;
}

ubus cleint

在這一部代碼中主要實現以下兩條命令:

ubus call YCY my_ubus_method_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'

ubus send my_notify '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}'

ubus client代碼

注意事項:

1.在命令行可以使用ubus call這樣的命令,那么代碼中如何調用另外進程的objetc的某個method是使用ubus_invoke函數,本例中將這個函數再進行了一層封裝方便使用。

2.在命令行可以使用ubus send這樣的命令,那么代碼中如何發送event是使用ubus_send_event函數,本例中將這個函數再進行了一層封裝方便使用。

3.請注意,在這個進程中,因為沒有常駐的ubus進程,所以可以將ubus call和ubus send這樣封裝成獨立的函數使用,如果本身這個ubus client也另外作為一個server運行了ubus常駐進程,就不可以按照我這里的封裝之后的函數使用,因為每個封裝之后的函數都有ctx的創建和free,這顯然和常駐進程的概念出現了沖突。


/* ubus send notify */

#define MY_UBUS_PARAM_NAME_1 "mac_addr"
#define MY_UBUS_PARAM_NAME_2 "ipv4_addr"

#define MY_UBUS_NOTIFY_EVENT    "my_notify"
#define MY_UBUS_NOTIFY_EVENT_1  "my_notify_1"

#define MY_UBUS_RETURN_STATUS  "status"
#define MY_UBUS_RETURN_ERR_STR "err_str"


struct ubus_context *g_ubus_ctx;
struct blob_buf g_ubus_buf;
struct ubud_event_handler g_ubus_notify;

enum
{
    RETURN_STATUS,
	RETURN_ERR_STR,	
	RETURN_MAX,
}

enum
{
    PARAM_MAC_ADDR,
	PARAM_IP4_ADDR,
	PARAM_MAX
}

static const struct blobmsg_policy my_ubus_policy[PARAM_MAX] = 
{
    [PARAM_MAC_ADDR] = {.name = MY_UBUS_PARAM_NAME_1, .type = BLOBMSG_TYPE_STRING},
	[PARAM_IP4_ADDR] = {.name = MY_UBUS_PARAM_NAME_2, .type = BLOBMSG_TYPE_STRING},
};

static const struct blobmsg_policy my_ubus_return_policy[PARAM_MAX] = 
{
    [RETURN_STATUS] =  {.name = MY_UBUS_RETURN_STATUS, .type = BLOBMSG_TYPE_INT32},
	[RETURN_ERR_STR] = {.name = MY_UBUS_RETURN_ERR_STR, .type = BLOBMSG_TYPE_STRING},
};

static int my_ubus_call_method(struct ubus_context *ubus_ctx,
								char *ubus_name,
								char *ubus_method,
								struct blob_buf b_buf,
								ubus_data_handler_t cb)
{
	unsigned int id = 0;
	int ret;
	
	ret =  ubus_lookup_id(ubus_ctx, ubus_name, &id);
	if (0 != ret)
	{
		printf("Error. Can't find %s\n", ubus_name);
	}

	return ubus_invoke(ubus_ctx, id, ubus_method, b_buf.head, cb, NULL, 0);
}

static int my_invoke_ubus_init(struct ubus_context **ctx)
{
	uloop_init();
	signal(SIGPIPE, SIG_IGN);

	*ctx = ubus_connect(NULL);
	if (NULL == *ctx)
	{
		printf("ubus connect failed\n");
		return -1;
	}

	ubus_add_uloop(*ctx);
	return 0;
}

static void my_ubus_ctx_exit(struct ubus_context **ctx)
{
	if (*ctx)
		ubus_free(*ctx);
}

static void cb_reply_status(struct ubus_request *req, int type, struct blob_attr *msg)
{
	struct blob_attr *tb[RETURN_MAX];
	int status = 0;
	char err_str[128] = {0};

	blobmsg_parse(return_policy1, RETURN_MAX, tb, blob_data(msg), blob_len(msg));
	if(tb[RETURN_STATUS] != NULL)
	{
	    status = blobmsg_get_u32(tb[RETURN_STATUS]);
	}
	else 
	{
	    printf("cb_reply_status :status can't pick out\n");
	}

	if(status == 0)//success
	{
	    /* TO DO with status */
	    printf("%d\n", status);
		return ;
	}
	else 
	{
	    if(tb[RETURN_ERR_STR] != NULL)
    	{
    	    strlcpy(err_str, blobmsg_get_string(tb[RETURN_ERR_STR]), 32);
    	}
		else 
		{
		    printf("cb_reply_status :err_str can't pick out\n");
		}
	}

}

int ubus_call_object_method_with_params(char *macaddr, char *ipv4_addr)
{
	int ret = -1;
	ret = my_invoke_ubus_init(&g_ubus_ctx);
	if (0 != ret)
	{
		printf("ubus init failed\n");
		return -1;
	}

	/* add params */
	blob_buf_init(&g_ubus_buf, 0);
	blobmsg_add_string(&g_ubus_buf, MY_UBUS_PARAM_NAME_1, macaddr);
	blobmsg_add_string(&g_ubus_buf, MY_UBUS_PARAM_NAME_2, ipv4_addr);
	
	/* ubus call YCY my_ubus_method_1 */
	my_ubus_call_method(g_ubus_ctx, MY_UBUS_OBJECT_NAME, MY_UBUS_METHOD_1, g_ubus_buf, cb_reply_status);

	my_ubus_ctx_exit(&g_ubus_ctx);
	return 0;
}

int ubus_send_event_with_params(char *macaddr, char *ipv4_addr)
{
	int ret = -1;
	ret = my_invoke_ubus_init(&g_ubus_ctx);
	if (0 != ret)
	{
		printf("ubus init failed\n");
		return -1;
	}

	/* add params */
	blob_buf_init(&g_ubus_buf, 0);
	blobmsg_add_string(&g_ubus_buf, MY_INVOKE_PARAMS_1, macaddr);
	blobmsg_add_string(&g_ubus_buf, MY_INVOKE_PARAMS_2, ipv4_addr);
	
	/* ubus send my_notify */
	ubus_send_event(g_ubus_ctx, MY_UBUS_NOTIFY_EVENT, g_ubus_buf.head);

	my_ubus_ctx_exit(&g_ubus_ctx);
	return 0;
}

int main()
{
    char macaddr[] = "60:03:4f:a0:52:51", 
	char ipv4_addr[] = "192.22.1.2",

	/* ubus call YCY my_ubus_method_1 '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}' */
    ubus_call_object_method_with_params(macaddr, ipv4_addr);


    /* ubus send my_notify '{"mac_addr":"60:03:4f:a0:52:51","ipv4_addr":"192.2.1.2"}' */
	ubus_send_event_with_params(macaddr, ipv4_addr);

	
    return 0;
}

ubus傳輸過程使用的blob數據我認為也有必要弄清楚一下,在下一篇文章中總結。

以上結束,這兩種使用法已經基本涵蓋了日常使用的部分。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM