zoukankan      html  css  js  c++  java
  • libubox-blob/blobmsg

    大部分内容来自libubox [3] - BLOB BLOGMSG,推荐阅读原文。

    blob提供二进制数据处理能力。有几种支持的数据类型,并可以创建块数据在socket上发送。整型数字会在libubox库内部转换为网络字节序进行处理。

    二进制块的处理方法是创建一个TLV(类型-长度-值)链表数据,支持嵌套类型数据,并提供设置和获取数据接口。blob定义在blob.h中。

    blogmsg位于blob的上层,提供表格和数组等数据类型的处理,定义在blogmsg.h中。

    TLV是用于表示可变长度的数据格式,Type表示数据的类型,length表示数据长度,value存储数据值。类型和长度的占用空间是固定的,在libubox库中共占用4个字节。

    Value的长度由length指定。这样可以存储和传输任何类型的数据,只需预先定义服务器和客户端之间的TLV的类型和长度的空间大小即可。

    一. blob

    blob(binary large object),二进制大对象,用于二进制对象序列化;blob主要在一些系统级组件(ubox/libubox/ubus/netifd)内部使用,一般应用不需要使用blob封装,blob用数据结构blob_attr表示。

    blob_buf用于管理(多个)二进制大对象。

     1. 数据结构

    #define BLOB_COOKIE     0x01234567
    
    enum {
        BLOB_ATTR_UNSPEC,
        BLOB_ATTR_NESTED,
        BLOB_ATTR_BINARY,
        BLOB_ATTR_STRING,
        BLOB_ATTR_INT8,
        BLOB_ATTR_INT16,
        BLOB_ATTR_INT32,
        BLOB_ATTR_INT64,
        BLOB_ATTR_LAST
    };
    
    #define BLOB_ATTR_ID_MASK  0x7f000000
    #define BLOB_ATTR_ID_SHIFT 24
    #define BLOB_ATTR_LEN_MASK 0x00ffffff
    #define BLOB_ATTR_ALIGN    4       //blob字节对齐
    #define BLOB_ATTR_EXTENDED 0x80000000
    
    // blob数据结构 struct blob_attr { uint32_t id_len; //id占用最高字节,msb用于扩展,len占用低3个字节 char data[]; } __packed; // 属性过滤 struct blob_attr_info { unsigned int type; unsigned int minlen; unsigned int maxlen; bool (*validate)(const struct blob_attr_info *, struct blob_attr *); };
    // 多个blob管理数据结构
    struct blob_buf { struct blob_attr *head; // 指向blob_buf的开头,分配一个4字节的blob_attr(仅有id_len),记录已使用的len。最初时等于blob_buf->buf bool (*grow)(struct blob_buf *buf, int minlen); //内存扩展回调函数 int buflen; //buf总长度 void *buf; // 指向buf起始位置(开头) };

    2. 函数

     获取blob属性

    /**
     * 返回指向BLOB属性数据区指针
     */
    static inline void * blob_data(const struct blob_attr *attr)
    
    /**
     * 返回BLOB属性ID
     */
    static inline unsigned int blob_id(const struct blob_attr *attr)
    
    /**
     * 判断BLOB属性扩展标志是否为真
     */
    static inline bool blob_is_extended(const struct blob_attr *attr)
    
    /**
     * 返回BLOB属性有效存储空间大小
     */
    static inline unsigned int blob_len(const struct blob_attr *attr)
    
    /*
     * 返回BLOB属性完全存储空间大小(包括头部)
     */
    static inline unsigned int blob_raw_len(const struct blob_attr *attr)
    
    /*
     * 返回BLOB属性填补后存储空间大小(包括头部),存储空间补齐大小
     */
    static inline unsigned int blob_pad_len(const struct blob_attr *attr)
    {
        unsigned int len = blob_raw_len(attr);
        len = (len + BLOB_ATTR_ALIGN - 1) & ~(BLOB_ATTR_ALIGN - 1);
        return len;
    }

    获取blob数据

    static inline uint8_t blob_get_u8(const struct blob_attr *attr)
    
    static inline uint16_t blob_get_u16(const struct blob_attr *attr)
    
    static inline uint32_t blob_get_u32(const struct blob_attr *attr)
    
    static inline uint64_t blob_get_u64(const struct blob_attr *attr)
    
    static inline int8_t blob_get_int8(const struct blob_attr *attr)
    
    static inline int16_t blob_get_int16(const struct blob_attr *attr)
    
    static inline int32_t blob_get_int32(const struct blob_attr *attr)
    
    static inline int64_t blob_get_int64(const struct blob_attr *attr)
    
    static inline const char * blob_get_string(const struct blob_attr *attr)

    设置blob数据

    static inline struct blob_attr *
    blob_put_string(struct blob_buf *buf, int id, const char *str)
    
    static inline struct blob_attr *
    blob_put_u8(struct blob_buf *buf, int id, uint8_t val)
    
    static inline struct blob_attr *
    blob_put_u16(struct blob_buf *buf, int id, uint16_t val)
    
    static inline struct blob_attr *
    blob_put_u32(struct blob_buf *buf, int id, uint32_t val)
    
    static inline struct blob_attr *
    blob_put_u64(struct blob_buf *buf, int id, uint64_t val)
    
    #define blob_put_int8   blob_put_u8
    #define blob_put_int16  blob_put_u16
    #define blob_put_int32  blob_put_u32
    #define blob_put_int64  blob_put_u64
    
    /**
     * ptr - 指向struct blob_attr
     */
    struct blob_attr * blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len)  

    struct blob_attr * blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len)

    遍历

    static inline struct blob_attr *
    blob_next(const struct blob_attr *attr)
    {
        return (struct blob_attr *) ((char *) attr + blob_pad_len(attr));
    }

    #define
    __blob_for_each_attr(pos, attr, rem) for (pos = (void *) attr; rem > 0 && (blob_pad_len(pos) <= rem) && (blob_pad_len(pos) >= sizeof(struct blob_attr)); rem -= blob_pad_len(pos), pos = blob_next(pos)) #define blob_for_each_attr(pos, attr, rem) for (rem = attr ? blob_len(attr) : 0, pos = attr ? blob_data(attr) : 0; rem > 0 && (blob_pad_len(pos) <= rem) && (blob_pad_len(pos) >= sizeof(struct blob_attr)); rem -= blob_pad_len(pos), pos = blob_next(pos))

    复制

    extern struct blob_attr *blob_memdup(struct blob_attr *attr);

    嵌套

    extern void *blob_nest_start(struct blob_buf *buf, int id);
    extern void blob_nest_end(struct blob_buf *buf, void *cookie);

    判断

    bool blob_check_type(const void *ptr, unsigned int len, int type);
    bool blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2);

    初始化和销毁

    blob_buf一般声明为本地静态变量,id一般使用0(BLOBMSG_TYPE_UNSPEC)来初始化。

    /**
     * 初始化BLOB buffer
     */
    int blob_buf_init(struct blob_buf *buf, int id)
    
    /**
     * 销毁BLOB buffer
     */
    void blob_buf_free(struct blob_buf *buf)

    解析blob

    /**
     * 从attr串中根据info策略过滤,得到的结果存储在data属性数组中
     *
     * @param  attr 输入BLOB属性串
     * @param  data 输出BLOB属性数组
     * @param  info 属性过滤策略
     * @param  max data数组大小
     */
    int blob_parse(struct blob_attr *attr, struct blob_attr **data, 
                   const struct blob_attr_info *info, int max)

    二. blobmsg

    blobmsg用于二进制对象网络序列化。嵌套在blob数据结构(blob_attr)的data区。因此形成:blob_buff <- blob_attr -< blobmsg,blob_buff可存储管理多个blob_attr,每个blob_attr又可存储管理一个blogmsg。且可存储在线性数据区,不需要链表指针。

    blobmsg_policy用于解析和缓存blobmsg列表,一般声明为一个静态数组,用于指导消息解析。

    blobmsg默认使用id为table。array类似C语言的数组,table类似C的结构

    1. 数据结构

    #define BLOBMSG_ALIGN   2
    #define BLOBMSG_PADDING(len) (((len) + (1 << BLOBMSG_ALIGN) - 1) & ~((1 << BLOBMSG_ALIGN) - 1))
    
    enum blobmsg_type {
        BLOBMSG_TYPE_UNSPEC,
        BLOBMSG_TYPE_ARRAY,
        BLOBMSG_TYPE_TABLE,
        BLOBMSG_TYPE_STRING,
        BLOBMSG_TYPE_INT64,
        BLOBMSG_TYPE_INT32,
        BLOBMSG_TYPE_INT16,
        BLOBMSG_TYPE_INT8,
        __BLOBMSG_TYPE_LAST,
        BLOBMSG_TYPE_LAST = __BLOBMSG_TYPE_LAST - 1,
        BLOBMSG_TYPE_BOOL = BLOBMSG_TYPE_INT8,
    };
    
    struct blobmsg_hdr {
        uint16_t namelen;
        uint8_t name[];
    } __packed;
    
    // 解析blobmsg列表
    struct blobmsg_policy { const char *name; // 与blobmsg_hdr->name对应 enum blobmsg_type type; // 策略值的类型,数据打包解包时作为blob_attr id };

    2. 获取blogmsg属性

    /**
     * 根据BLOB消息名字长度计算出blobmsg头部大小
     */
    static inline int blobmsg_hdrlen(unsigned int namelen)
    
    /**
     * 获取BLOB消息名字
     */
    static inline const char *blobmsg_name(const struct blob_attr *attr)
    
    /**
     * 获取BLOB消息类型
     */
    static inline int blobmsg_type(const struct blob_attr *attr)
    
    /**
     * 获取BLOB消息数据内容
     */
    static inline void *blobmsg_data(const struct blob_attr *attr)
    
    /**
     * 获取BLOB消息数据内容大小
     */
    static inline int blobmsg_data_len(const struct blob_attr *attr)
    {
        uint8_t *start, *end;

        start = (uint8_t *) blob_data(attr);
        end = (uint8_t *) blobmsg_data(attr);

        return blob_len(attr) - (end - start);
    }
    static inline int blobmsg_len(const struct blob_attr *attr)
    {
        return blobmsg_data_len(attr);
    }

    3. 数据类型判断

    /**
     * 判断BLOBMSG属性类型是否合法
     */
    bool blobmsg_check_attr(const struct blob_attr *attr, bool name)

    4. 设置

    int blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
                          const void *data, unsigned int len)
    
    static inline int
    blobmsg_add_u8(struct blob_buf *buf, const char *name, uint8_t val)
    
    static inline int
    blobmsg_add_u16(struct blob_buf *buf, const char *name, uint16_t val)
    
    static inline int
    blobmsg_add_u32(struct blob_buf *buf, const char *name, uint32_t val)
    
    static inline int
    blobmsg_add_u64(struct blob_buf *buf, const char *name, uint64_t val)
    
    static inline int
    blobmsg_add_string(struct blob_buf *buf, const char *name, const char *string)
    
    static inline int
    blobmsg_add_blob(struct blob_buf *buf, struct blob_attr *attr)
    
    /**
     * 格式化设备BLOGMSG
     */
    void blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)

    5. 获取

    static inline uint8_t blobmsg_get_u8(struct blob_attr *attr)
    static inline bool blobmsg_get_bool(struct blob_attr *attr)
    static inline uint16_t blobmsg_get_u16(struct blob_attr *attr)
    static inline uint32_t blobmsg_get_u32(struct blob_attr *attr)
    static inline uint64_t blobmsg_get_u64(struct blob_attr *attr)
    static inline char *blobmsg_get_string(struct blob_attr *attr)

    6. 创建

    /**
     * 创建BLOBMSG,返回数据区开始地址
     */
    void *blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen)
    
    /**
     * 扩大BLOGMSG,返回数据区开始地址
     */
    void *blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen)
    
    void blobmsg_add_string_buffer(struct blob_buf *buf)

    7. 遍历

    #define blobmsg_for_each_attr(pos, attr, rem) 
        for (rem = attr ? blobmsg_data_len(attr) : 0, 
             pos = attr ? blobmsg_data(attr) : 0; 
             rem > 0 && (blob_pad_len(pos) <= rem) && 
             (blob_pad_len(pos) >= sizeof(struct blob_attr)); 
             rem -= blob_pad_len(pos), pos = blob_next(pos))

    8. 嵌套

    static inline void * blobmsg_open_array(struct blob_buf *buf, const char *name)
    static inline void blobmsg_close_array(struct blob_buf *buf, void *cookie)
    
    static inline void *blobmsg_open_table(struct blob_buf *buf, const char *name)
    static inline void blobmsg_close_table(struct blob_buf *buf, void *cookie)

    9. 解析blogmsg

    /**
     * 从data BLOGMSG串中根据policy策略过滤,得到的结果存储在tb BLOGATTR数组中
     *
     * @param  policy 过滤策略
     * @param  policy_len 策略个数
     * @param  tb 返回属性数据
     * @param  len data属性个数
     */
    int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
                      struct blob_attr **tb, void *data, unsigned int len)

     blobmsg根节点是一个纯粹的blob,所以blobmsg解析时需要注意:
    (1)第一层解析,data必须取值为blob_data(root_blob),len必须取值为blob_len(root_blob)
    (2)第二层及以上解析,data必须取值为blobmsg_data(sub_blob),len必须取值为blobmsg_data_len(sub_blob)
    所以,应避免混合使用blob和blobmsg语义,比如第一层使用blob语义,第二层使用blobmsg语义。

    三. blobmsg_json

    blobmsg_json用于json对象的序列化,json提供脚本级消息发送机制,如果应用需要脚本配合,则需要使用json。

    四. 示例

    UCI配置文件: /etc/config/test

    config policy test
        option name 'test'
        option enable '1'
        option dns '1.1.1.1 2.2.2.2'

    定义参数列表

    enum {
        POLICY_ATTR_NAME,       /** name */
        POLICY_ATTR_ENABLE,     /** enable */
        POLICY_ATTR_DNS,        /** dns */
        __POLICY_ATTR_MAX
    };
    
    static const struct blobmsg_policy policy_attrs[__POLICY_ATTR_MAX] = {
        [POLICY_ATTR_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
        [POLICY_ATTR_ENABLE] = { .name = "enable", .type = BLOBMSG_TYPE_BOOL },
        [POLICY_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
    };
    
    /** 定义BLOBMSG_TYPE_ARRAY类型参数的实际数据类型 */
    static const struct uci_blob_param_info policy_attr_info[__POLICY_ATTR_MAX] = {
        [POLICY_ATTR_DNS] = { .type = BLOBMSG_TYPE_STRING },
    };
    
    static const struct uci_blob_param_list policy_attr_list = {
        .n_params = __POLICY_ATTR_MAX,
        .params = policy_attrs,
        .info = policy_attr_info,
    };

    转化为blob

    static struct uci_context *g_uci_ctx;
    static struct blob_buf *b;
    
    void
    transform(const char *config)
    {
        struct uci_context *ctx = g_uci_ctx;
        struct uci_package *p = NULL;
    
        if (!ctx) {
            ctx = uci_alloc_context();
            g_uci_ctx = ctx;
            uci_set_confdir(ctx, NULL);
        } else {
            p = uci_lookup_package(ctx, config);
            if (p)
                uci_unload(ctx, p);
        }
    
        if (uci_load(ctx, config, &p))
            return;    
    
        struct uci_element *e;
        struct blob_attr *config = NULL;
        uci_foreach_element(&p->sectons, e) {
            struct uci_section *s = uci_to_section(e);
    
            blob_buf_init(&b, 0);
            uci_to_blob(&b, s, &policy_attr_list);
            config = blob_memdup(b.head);
    
            /**
             * do something with `config` 
             * free(config), when not use it
             */
        }
    }

    使用转换后的blob

    void
    foo(blob_attr *confg)
    {
        struct blob_attr *tb[__POLICY_ATTR_MAX];
    
        blobmsg_parse(policy_attrs, __POLICY_ATTR_MAX, tb,
                blob_data(config), blob_len(config));
    
        /**
         * do something with *tb[] 
         */
    }
  • 相关阅读:
    重置root密码
    JavaEE完整体系架构
    Analysis servlet injection
    隔离级别
    ULVAC爱发科皮拉尼真空计SW1-N说明书-手册
    研华advantech-凌华ADLINK板卡运动控制卡
    vc6.0转vs2012的一些错误与解决方法
    MFC时间简单比较方法
    MFC_VC++_时间获取与保存列表控件内容到文件操作方法
    show and hide. xp扩展名
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/6792359.html
Copyright © 2011-2022 走看看