zoukankan      html  css  js  c++  java
  • 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
    ");
    		return -1;
    	}
    
    	ret = ubus_add_object(g_ubus_ctx, &g_ubus_object_1);
    	if (ret != 0)
    	{
    		printf("failed to add object to ubus
    ");
    		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
    ", 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
    ");
    	uloop_init();
    
    	g_ubus_ctx = ubus_connect(NULL);
    	if (g_ubus_ctx == NULL)
    	{
    		printf("failed to connect to ubus
    ");
    		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
    ");
    		return -1;
    	}
    	
    	/* ubus register events */
    	my_ubus_register_event_all();
    	if (ret != 0)
    	{
    		printf("failed to register event to ubus
    ");
    		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
    ", ubus_strerror(ret));
    		return -1;
    	}
    
    	/* free resource */
    	ubus_free(g_ubus_ctx);
    	uloop_done();
    	printf("return out of uloop_run
    ");
    
    	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
    ");
    		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
    ");
    		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
    ", 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
    ");
    		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
    ");
    	}
    
    	if(status == 0)//success
    	{
    	    /* TO DO with status */
    	    printf("%d
    ", 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
    ");
    		}
    	}
    
    }
    
    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
    ");
    		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
    ");
    		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数据我认为也有必要弄清楚一下,在下一篇文章中总结。

    以上结束,这两种使用法已经基本涵盖了日常使用的部分。

  • 相关阅读:
    CodeForces Gym 100500A A. Poetry Challenge DFS
    CDOJ 486 Good Morning 傻逼题
    CDOJ 483 Data Structure Problem DFS
    CDOJ 482 Charitable Exchange bfs
    CDOJ 481 Apparent Magnitude 水题
    Codeforces Gym 100637G G. #TheDress 暴力
    Gym 100637F F. The Pool for Lucky Ones 暴力
    Codeforces Gym 100637B B. Lunch 找规律
    Codeforces Gym 100637A A. Nano alarm-clocks 前缀和
    TC SRM 663 div2 B AABB 逆推
  • 原文地址:https://www.cnblogs.com/y-c-y/p/14682397.html
Copyright © 2011-2022 走看看