OpenWrt源码分析之libubox

来源:互联网 发布:芈月怎么玩 知乎 编辑:程序博客网 时间:2024/06/05 03:24

json

OpenWrt支持c、shell、lua三种语言的进程通过ubus进行进程间通讯,ubus通讯的消息格式遵循json格式。

json(JavaScript object Notation)是一种轻量级的数据交换格式,易于人读写,也易于机器解析和生成。json是一种独立于编程语言之外的文本格式,兼容多种编程语言,如c、c++、Java、JavaScript、perl、Python等。

json由两种格式组成:

  1. string
    格式是key:value,value为字符串;
    object是一个name/vale对,格式是{name:value},相当于c语言中的结构体、哈希表等。

  2. number
    格式是key:value,value为整数;

  3. boolean
    格式是key:value,value为1或者0;

  4. object
    object相当于c语言中中的结构体,格式是key:{key1:value1,key2:value2,…},value可以是string、number、boolean、object或者array;

  5. array
    array相当于c语言中的数组,格式是key:[value1,value2,…],value可以是string、number、boolean、object或者array。

OpenWrt shell程序中用到了命令jshn和脚本jshn.sh;
下面是一个shell程序中使用json的例子:

. /usr/share/libubox/jshn.sh# generating json datajson_initjson_add_string "str" "Hello, world!"json_add_object "obj"json_add_int "num" "100"json_add_boolean "bool" "0"json_close_objectjson_add_array "array"json_add_string "arraystr" "array string"json_add_int "" "110"json_add_boolean "" "1"json_close_arrayMSG=`json_dump`echo ${MSG}# parsing json datajson_load "$MSG"json_get_var varstr strjson_select objjson_get_var varnum numjson_get_var varbool booljson_select ..json_select arrayjson_get_var array1 "1"json_get_var array2 "2"json_get_var array3 "3"cat << EOF{  msg : $varstr,  obj: {      num : $varnum,      bool : $varbool },  array: [ $array1, $array2, $array3 ]}

执行结果为:

root@OpenWrt:/# ./jsontest.sh{ "str": "Hello, world!", "obj": { "num": 100, "bool": false }, "array": [ "array string", 110, true ] }{  msg : Hello, world!,  obj: {      num : 100,      bool : 0 },  array: [ array string, 110, 1 ]}

shell json相关的api函数有:

函数 描述 json_init
json_cleanup 初始化json环境
清空json环境 json_add_string 添加string类型的element json_add_int 添加int类型的element json_add_boolean 添加boolean类型的element json_add_table
json_close_table 添加table类型的element json_add_array
json_close_array 添加array类型的element json_load 从字符串中导入到json格式 json_select 进入到某个element,必须有是table或array才能使用json_select json_get_keys 获取所有element的key json_get_values 获取所有element的value json_get_var 根据key获取value json_get_type 获取element的类型

blob & blobmsg

ubus之间传递的消息在程序中使用blob或者blobmsg的形式组织,blob是一种二进制字节序列,在libubox中,blob使用结构体struct blob_attr表示,如下所示:

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

在内存中,一个blob数据的格式如下所示:
这里写图片描述

blob是符合TLV格式的,TLV表示Type-Length-Value,上图中,ID即使Type,Len即是Length,Payload即是Value。

blobmsg是在blob的基础上扩展出来的,blobmsg的格式如下图所示:
这里写图片描述

blobmsg中扩展标准位extended等于1,payload拆分出key和value两个字段,ID表示blogmsg的类型,类型包括BLOBMSG_TYPE_STRING、BLOBMSG_TYPE_INT、BLOBMSG_TYPE_BOOL、BLOBMSG_TYPE_TABLE、BLOBMSG_TYPE_ARRAY。

  • string、int、bool类型blobmsg
    类似于json,string类型的blobmsg的格式如下:
    这里写图片描述
    string类型的blobmsg的value为string,int和bool类型的blobmsg的value为对应类型的值。

  • table、array类型blobmsg
    类似于json,table类型的blobmsg相当于object类型的json,相当于c语言中的结构体,array相当于c语言中的数组;
    table类型的blobmsg格式如下图所示:
    这里写图片描述
    array类型的blobmsg格式如下图所示:
    这里写图片描述
    array和table十分相似,区别在于array的元素是不需要key名字的。

一般使用结构体blob_buf来表示blobmsg链表,blob_buf的head和buf(之所以要用两个指针是因为在加到blobmsg长度时,重新申请连续内存指针会发生改变)都指向一个table类型的blobmsg,buflen等于总长度;
格式如下所示:

blob或者blobmsg常用的api如下所示:

  • string
    blobmsg_add_string
    blobmsg_get_string

  • int
    blobmsg_add_u8
    blobmsg_add_u16
    blobmsg_add_u32
    blobmsg_add_u64
    blobmsg_get_u8
    blobmsg_get_u16
    blobmsg_get_u32
    blobmsg_get_u64

  • bool
    bool转换成u8的0或者1

  • table
    blobmsg_open_table
    blobmsg_close_table

/* * Example: * * table_key : { *     string_key : "this is a string", *     int_key : 100, *     bool_key : true */}static struct blob_buf buf;blobmsg_buf_init(&buf);void *tbl = blobmsg_open_table(buf, "table_key");blobmsg_add_string(buf, "string_key", "this is a string");blobmsg_add_u8(buf, "int_key", 100);blobmsg_add_u8(buf, "bool_key", 1);blobmsg_close_table(buf, tbl);
  • array
    blobmsg_open_array
    blobmsg_close_array
/* * Example: * * array_key : [ "this is a string", 100, true ] */static struct blob_buf buf;blobmsg_buf_init(&buf);void *array = blobmsg_open_array(buf, "array_key");blobmsg_add_string(buf, NULL, "this is a string");blobmsg_add_u8(buf, NULL, 100);blobmsg_add_u8(buf, NULL, 1);blobmsg_close_array(buf, array);
  • parse
    blobmsg_parse
//上面两个例子中添加table和array到buf中去,下面将其取出来enum {        FOO_TABLE,        FOO_ARRAY};static const struct blobmsg_policy pol[] = {        [FOO_TABLE] = {                .name = "table_key",                .type = BLOBMSG_TYPE_TABLE,        },        [FOO_ARRAY] = {                .name = "array_key",                .type = BLOBMSG_TYPE_ARRAY,        },};struct blob_attr *tb[ARRAY_SIZE(pol)];blobmsg_parse(pol, ARRAY_SIZE(pol), tb, blob_data(buf->head); //parse/* after parse * tb[FOO_TABLE] is table blobmsg * tb[FOO_ARRAY] is array blobmsg * blobmsg_data(tb[FOO_TABLE] get table element head * __blob_for_each_attr(attr, head, len) get every element * /