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的类型和长度的空间大小即可。

1.blob

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

1.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起始位置(开头)
};

 1.2.函数

1.2.1获取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;
}

1.2.2获取blob数据

//获取uint8_t类型数据并返回
static inline uint8_t blob_get_u8(const struct blob_attr *attr)

//获取uint16_t类型数据并返回
static inline uint16_t blob_get_u16(const struct blob_attr *attr)

//获取uint32_t类型数据并返回
static inline uint32_t blob_get_u32(const struct blob_attr *attr)

//获取uint64_t类型数据并返回
static inline uint64_t blob_get_u64(const struct blob_attr *attr)

//获取int8_t类型数据并返回
static inline int8_t blob_get_int8(const struct blob_attr *attr)

//获取int16_t类型数据并返回
static inline int16_t blob_get_int16(const struct blob_attr *attr)

//获取int32_t类型数据并返回
static inline int32_t blob_get_int32(const struct blob_attr *attr)

//获取int64_t类型数据并返回
static inline int64_t blob_get_int64(const struct blob_attr *attr)

//获取const char* 类型数据并返回
static inline const char * blob_get_string(const struct blob_attr *attr)

1.2.3设置blob数据

//将str设置到buf数据结构中
static inline struct blob_attr *
blob_put_string(struct blob_buf *buf, int id, const char *str)

//将val设置到buf数据结构中
static inline struct blob_attr *
blob_put_u8(struct blob_buf *buf, int id, uint8_t val)

//将val设置到buf数据结构中
static inline struct blob_attr *
blob_put_u16(struct blob_buf *buf, int id, uint16_t val)

//将val设置到buf数据结构中
static inline struct blob_attr *
blob_put_u32(struct blob_buf *buf, int id, uint32_t val)

//将val设置到buf数据结构中
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)

1.2.4遍历

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))

1.2.5复制

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

1.2.6 嵌套

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

1.2.7判断

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);

1.2.8 初始化和销毁

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)

1.2.9解析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)

2.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的结构

2.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.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);
}

2.3数据类型判断

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

2.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, ...)

2.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)

2.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)

2.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))

2.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)

2.9解析blobmsg

/*
 * 从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语义

3.blob_msg

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

4.举例

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

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

4.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,
};

4.3转化为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
         */
    }
}

4.4使用转化后的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[] 
     */
}

5.相关文件

5.1uci.h

/*
 * libuci - Library for the Unified Configuration Interface
 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 */

#ifndef __LIBUCI_H
#define __LIBUCI_H

#ifdef __cplusplus
extern "C" {
#endif

#include "uci_config.h"

/*
 * you can use these defines to enable debugging behavior for
 * apps compiled against libuci:
 *
 * #define UCI_DEBUG_TYPECAST:
 *   enable uci_element typecast checking at run time
 *
 */

#include <stdbool.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdint.h>

#define UCI_CONFDIR "/etc/config"
#define UCI_SAVEDIR "/tmp/.uci"
#define UCI_DIRMODE 0700
#define UCI_FILEMODE 0600

enum
{
	UCI_OK = 0,
	UCI_ERR_MEM,
	UCI_ERR_INVAL,
	UCI_ERR_NOTFOUND,
	UCI_ERR_IO,
	UCI_ERR_PARSE,
	UCI_ERR_DUPLICATE,
	UCI_ERR_UNKNOWN,
	UCI_ERR_LAST
};

struct uci_list;
struct uci_list
{
	struct uci_list *next;
	struct uci_list *prev;
};

struct uci_ptr;
struct uci_element;
struct uci_package;
struct uci_section;
struct uci_option;
struct uci_delta;
struct uci_context;
struct uci_backend;
struct uci_parse_option;
struct uci_parse_context;


/**
 * uci_alloc_context: Allocate a new uci context
 */
extern struct uci_context *uci_alloc_context(void);

/**
 * uci_free_context: Free the uci context including all of its data
 */
extern void uci_free_context(struct uci_context *ctx);

/**
 * uci_perror: Print the last uci error that occured
 * @ctx: uci context
 * @str: string to print before the error message
 */
extern void uci_perror(struct uci_context *ctx, const char *str);

/**
 * uci_geterror: Get an error string for the last uci error
 * @ctx: uci context
 * @dest: target pointer for the string
 * @str: prefix for the error message
 *
 * Note: string must be freed by the caller
 */
extern void uci_get_errorstr(struct uci_context *ctx, char **dest, const char *str);

/**
 * uci_import: Import uci config data from a stream
 * @ctx: uci context
 * @stream: file stream to import from
 * @name: (optional) assume the config has the given name
 * @package: (optional) store the last parsed config package in this variable
 * @single: ignore the 'package' keyword and parse everything into a single package
 *
 * the name parameter is for config files that don't explicitly use the 'package <...>' keyword
 * if 'package' points to a non-null struct pointer, enable delta tracking and merge
 */
extern int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_package **package, bool single);

/**
 * uci_export: Export one or all uci config packages
 * @ctx: uci context
 * @stream: output stream
 * @package: (optional) uci config package to export
 * @header: include the package header
 */
extern int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *package, bool header);

/**
 * uci_load: Parse an uci config file and store it in the uci context
 *
 * @ctx: uci context
 * @name: name of the config file (relative to the config directory)
 * @package: store the loaded config package in this variable
 */
extern int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package);

/**
 * uci_unload: Unload a config file from the uci context
 *
 * @ctx: uci context
 * @package: pointer to the uci_package struct
 */
extern int uci_unload(struct uci_context *ctx, struct uci_package *p);

/**
 * uci_lookup_ptr: Split an uci tuple string and look up an element tree
 * @ctx: uci context
 * @ptr: lookup result struct
 * @str: uci tuple string to look up
 * @extended: allow extended syntax lookup
 *
 * if extended is set to true, uci_lookup_ptr supports the following
 * extended syntax:
 *
 * Examples:
 *   network.@interface[0].ifname ('ifname' option of the first interface section)
 *   network.@interface[-1]       (last interface section)
 * Note: uci_lookup_ptr will automatically load a config package if necessary
 * @str must not be constant, as it will be modified and used for the strings inside @ptr,
 * thus it must also be available as long as @ptr is in use.
 *
 * This function returns UCI_ERR_NOTFOUND if the package specified in the tuple
 * string cannot be found.  Otherwise it will return UCI_OK.
 *
 * Note that failures in looking up other parts, if they are also specfied,
 * including section and option, will also have a return value UCI_OK but with
 * ptr->flags * UCI_LOOKUP_COMPLETE not set.
 */
extern int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended);

/**
 * uci_add_section: Add an unnamed section
 * @ctx: uci context
 * @p: package to add the section to
 * @type: section type
 * @res: pointer to store a reference to the new section in
 */
extern int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res);

/**
 * uci_set: Set an element's value; create the element if necessary
 * @ctx: uci context
 * @ptr: uci pointer
 *
 * The updated/created element is stored in ptr->last
 */
extern int uci_set(struct uci_context *ctx, struct uci_ptr *ptr);

/**
 * uci_add_list: Append a string to an element list
 * @ctx: uci context
 * @ptr: uci pointer (with value)
 *
 * Note: if the given option already contains a string value,
 * it will be converted to an 1-element-list before appending the next element
 */
extern int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr);

/**
 * uci_del_list: Remove a string from an element list
 * @ctx: uci context
 * @ptr: uci pointer (with value)
 *
 */
extern int uci_del_list(struct uci_context *ctx, struct uci_ptr *ptr);

/**
 * uci_reorder: Reposition a section
 * @ctx: uci context
 * @s: uci section to reposition
 * @pos: new position in the section list
 */
extern int uci_reorder_section(struct uci_context *ctx, struct uci_section *s, int pos);

/**
 * uci_rename: Rename an element
 * @ctx: uci context
 * @ptr: uci pointer (with value)
 */
extern int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr);

/**
 * uci_delete: Delete a section or option
 * @ctx: uci context
 * @ptr: uci pointer
 */
extern int uci_delete(struct uci_context *ctx, struct uci_ptr *ptr);

/**
 * uci_save: save change delta for a package
 * @ctx: uci context
 * @p: uci_package struct
 */
extern int uci_save(struct uci_context *ctx, struct uci_package *p);

/**
 * uci_commit: commit changes to a package
 * @ctx: uci context
 * @p: uci_package struct pointer
 * @overwrite: overwrite existing config data and flush delta
 *
 * committing may reload the whole uci_package data,
 * the supplied pointer is updated accordingly
 */
extern int uci_commit(struct uci_context *ctx, struct uci_package **p, bool overwrite);

/**
 * uci_list_configs: List available uci config files
 * @ctx: uci context
 *
 * caller is responsible for freeing the allocated memory behind list
 */
extern int uci_list_configs(struct uci_context *ctx, char ***list);

/**
 * uci_set_savedir: override the default delta save directory
 * @ctx: uci context
 * @dir: directory name
 *
 * This will also try adding the specified dir to the end of delta pathes.
 */
extern int uci_set_savedir(struct uci_context *ctx, const char *dir);

/**
 * uci_set_savedir: override the default config storage directory
 * @ctx: uci context
 * @dir: directory name
 */
extern int uci_set_confdir(struct uci_context *ctx, const char *dir);

/**
 * uci_add_delta_path: add a directory to the search path for change delta files
 * @ctx: uci context
 * @dir: directory name
 *
 * This function allows you to add directories, which contain 'overlays'
 * for the active config, that will never be committed.
 *
 * Adding a duplicate directory will cause UCI_ERR_DUPLICATE be returned.
 */
extern int uci_add_delta_path(struct uci_context *ctx, const char *dir);

/**
 * uci_revert: revert all changes to a config item
 * @ctx: uci context
 * @ptr: uci pointer
 */
extern int uci_revert(struct uci_context *ctx, struct uci_ptr *ptr);

/**
 * uci_parse_argument: parse a shell-style argument, with an arbitrary quoting style
 * @ctx: uci context
 * @stream: input stream
 * @str: pointer to the current line (use NULL for parsing the next line)
 * @result: pointer for the result
 */
extern int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result);

/**
 * uci_set_backend: change the default backend
 * @ctx: uci context
 * @name: name of the backend
 *
 * The default backend is "file", which uses /etc/config for config storage
 */
extern int uci_set_backend(struct uci_context *ctx, const char *name);

/**
 * uci_validate_text: validate a value string for uci options
 * @str: value
 *
 * this function checks whether a given string is acceptable as value
 * for uci options
 */
extern bool uci_validate_text(const char *str);

/**
 * uci_parse_ptr: parse a uci string into a uci_ptr
 * @ctx: uci context
 * @ptr: target data structure
 * @str: string to parse
 *
 * str is modified by this function
 */
int uci_parse_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str);

/**
 * uci_lookup_next: lookup a child element
 * @ctx: uci context
 * @e: target element pointer
 * @list: list of elements
 * @name: name of the child element
 *
 * if parent is NULL, the function looks up the package with the given name
 */
int uci_lookup_next(struct uci_context *ctx, struct uci_element **e, struct uci_list *list, const char *name);

/**
 * uci_parse_section: look up a set of options
 * @s: uci section
 * @opts: list of options to look up
 * @n_opts: number of options to look up
 * @tb: array of pointers to found options
 */
void uci_parse_section(struct uci_section *s, const struct uci_parse_option *opts,
		       int n_opts, struct uci_option **tb);

/**
 * uci_hash_options: build a hash over a list of options
 * @tb: list of option pointers
 * @n_opts: number of options
 */
uint32_t uci_hash_options(struct uci_option **tb, int n_opts);


/* UCI data structures */
enum uci_type {
	UCI_TYPE_UNSPEC = 0,
	UCI_TYPE_DELTA = 1,
	UCI_TYPE_PACKAGE = 2,
	UCI_TYPE_SECTION = 3,
	UCI_TYPE_OPTION = 4,
	UCI_TYPE_PATH = 5,
	UCI_TYPE_BACKEND = 6,
	UCI_TYPE_ITEM = 7,
	UCI_TYPE_HOOK = 8,
};

enum uci_option_type {
	UCI_TYPE_STRING = 0,
	UCI_TYPE_LIST = 1,
};

enum uci_flags {
	UCI_FLAG_STRICT =        (1 << 0), /* strict mode for the parser */
	UCI_FLAG_PERROR =        (1 << 1), /* print parser error messages */
	UCI_FLAG_EXPORT_NAME =   (1 << 2), /* when exporting, name unnamed sections */
	UCI_FLAG_SAVED_DELTA = (1 << 3), /* store the saved delta in memory as well */
};

struct uci_element
{
	struct uci_list list;
	enum uci_type type;
	char *name;
};

struct uci_backend
{
	struct uci_element e;
	char **(*list_configs)(struct uci_context *ctx);
	struct uci_package *(*load)(struct uci_context *ctx, const char *name);
	void (*commit)(struct uci_context *ctx, struct uci_package **p, bool overwrite);

	/* private: */
	const void *ptr;
	void *priv;
};

struct uci_context
{
	/* list of config packages */
	struct uci_list root;

	/* parser context, use for error handling only */
	struct uci_parse_context *pctx;

	/* backend for import and export */
	struct uci_backend *backend;
	struct uci_list backends;

	/* uci runtime flags */
	enum uci_flags flags;

	char *confdir;
	char *savedir;

	/* search path for delta files */
	struct uci_list delta_path;

	/* private: */
	int err;
	const char *func;
	jmp_buf trap;
	bool internal, nested;
	char *buf;
	int bufsz;
};

struct uci_package
{
	struct uci_element e;
	struct uci_list sections;
	struct uci_context *ctx;
	bool has_delta;
	char *path;

	/* private: */
	struct uci_backend *backend;
	void *priv;
	int n_section;
	struct uci_list delta;
	struct uci_list saved_delta;
};

struct uci_section
{
	struct uci_element e;
	struct uci_list options;
	struct uci_package *package;
	bool anonymous;
	char *type;
};

struct uci_option
{
	struct uci_element e;
	struct uci_section *section;
	enum uci_option_type type;
	union {
		struct uci_list list;
		char *string;
	} v;
};

/*
 * UCI_CMD_ADD is used for anonymous sections or list values
 */
enum uci_command {
	UCI_CMD_ADD,
	UCI_CMD_REMOVE,
	UCI_CMD_CHANGE,
	UCI_CMD_RENAME,
	UCI_CMD_REORDER,
	UCI_CMD_LIST_ADD,
	UCI_CMD_LIST_DEL,
	__UCI_CMD_MAX,
	__UCI_CMD_LAST = __UCI_CMD_MAX - 1
};
extern char const uci_command_char[];

struct uci_delta
{
	struct uci_element e;
	enum uci_command cmd;
	char *section;
	char *value;
};

struct uci_ptr
{
	enum uci_type target;
	enum {
		UCI_LOOKUP_DONE =     (1 << 0),
		UCI_LOOKUP_COMPLETE = (1 << 1),
		UCI_LOOKUP_EXTENDED = (1 << 2),
	} flags;

	struct uci_package *p;
	struct uci_section *s;
	struct uci_option *o;
	struct uci_element *last;

	const char *package;
	const char *section;
	const char *option;
	const char *value;
};

struct uci_parse_option {
	const char *name;
	enum uci_option_type type;
};


/* linked list handling */
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 */
#ifndef container_of
#define container_of(ptr, type, member) \
	((type *) ((char *)ptr - offsetof(type,member)))
#endif


/**
 * uci_list_entry: casts an uci_list pointer to the containing struct.
 * @_type: config, section or option
 * @_ptr: pointer to the uci_list struct
 */
#define list_to_element(ptr) \
	container_of(ptr, struct uci_element, list)

/**
 * uci_foreach_entry: loop through a list of uci elements
 * @_list: pointer to the uci_list struct
 * @_ptr: iteration variable, struct uci_element
 *
 * use like a for loop, e.g:
 *   uci_foreach(&list, p) {
 *   	...
 *   }
 */
#define uci_foreach_element(_list, _ptr)		\
	for(_ptr = list_to_element((_list)->next);	\
		&_ptr->list != (_list);			\
		_ptr = list_to_element(_ptr->list.next))

/**
 * uci_foreach_entry_safe: like uci_foreach_safe, but safe for deletion
 * @_list: pointer to the uci_list struct
 * @_tmp: temporary variable, struct uci_element *
 * @_ptr: iteration variable, struct uci_element *
 *
 * use like a for loop, e.g:
 *   uci_foreach(&list, p) {
 *   	...
 *   }
 */
#define uci_foreach_element_safe(_list, _tmp, _ptr)		\
	for(_ptr = list_to_element((_list)->next),		\
		_tmp = list_to_element(_ptr->list.next);	\
		&_ptr->list != (_list);			\
		_ptr = _tmp, _tmp = list_to_element(_ptr->list.next))

/**
 * uci_list_empty: returns true if a list is empty
 * @list: list head
 */
#define uci_list_empty(list) ((list)->next == (list))

/* wrappers for dynamic type handling */
#define uci_type_backend UCI_TYPE_BACKEND
#define uci_type_delta UCI_TYPE_DELTA
#define uci_type_package UCI_TYPE_PACKAGE
#define uci_type_section UCI_TYPE_SECTION
#define uci_type_option UCI_TYPE_OPTION

/* element typecasting */
#ifdef UCI_DEBUG_TYPECAST
static const char *uci_typestr[] = {
	[uci_type_backend] = "backend",
	[uci_type_delta] = "delta",
	[uci_type_package] = "package",
	[uci_type_section] = "section",
	[uci_type_option] = "option",
};

static void uci_typecast_error(int from, int to)
{
	fprintf(stderr, "Invalid typecast from '%s' to '%s'\n", uci_typestr[from], uci_typestr[to]);
}

#define BUILD_CAST(_type) \
	static inline struct uci_ ## _type *uci_to_ ## _type (struct uci_element *e) \
	{ \
		if (e->type != uci_type_ ## _type) { \
			uci_typecast_error(e->type, uci_type_ ## _type); \
		} \
		return (struct uci_ ## _type *) e; \
	}

BUILD_CAST(backend)
BUILD_CAST(delta)
BUILD_CAST(package)
BUILD_CAST(section)
BUILD_CAST(option)

#else
#define uci_to_backend(ptr) container_of(ptr, struct uci_backend, e)
#define uci_to_delta(ptr) container_of(ptr, struct uci_delta, e)
#define uci_to_package(ptr) container_of(ptr, struct uci_package, e)
#define uci_to_section(ptr) container_of(ptr, struct uci_section, e)
#define uci_to_option(ptr)  container_of(ptr, struct uci_option, e)
#endif

/**
 * uci_alloc_element: allocate a generic uci_element, reserve a buffer and typecast
 * @ctx: uci context
 * @type: {package,section,option}
 * @name: string containing the name of the element
 * @datasize: additional buffer size to reserve at the end of the struct
 */
#define uci_alloc_element(ctx, type, name, datasize) \
	uci_to_ ## type (uci_alloc_generic(ctx, uci_type_ ## type, name, sizeof(struct uci_ ## type) + datasize))

#define uci_dataptr(ptr) \
	(((char *) ptr) + sizeof(*ptr))

/**
 * uci_lookup_package: look up a package
 * @ctx: uci context
 * @name: name of the package
 */
static inline struct uci_package *
uci_lookup_package(struct uci_context *ctx, const char *name)
{
	struct uci_element *e = NULL;
	if (uci_lookup_next(ctx, &e, &ctx->root, name) == 0)
		return uci_to_package(e);
	else
		return NULL;
}

/**
 * uci_lookup_section: look up a section
 * @ctx: uci context
 * @p: package that the section belongs to
 * @name: name of the section
 */
static inline struct uci_section *
uci_lookup_section(struct uci_context *ctx, struct uci_package *p, const char *name)
{
	struct uci_element *e = NULL;
	if (uci_lookup_next(ctx, &e, &p->sections, name) == 0)
		return uci_to_section(e);
	else
		return NULL;
}

/**
 * uci_lookup_option: look up an option
 * @ctx: uci context
 * @section: section that the option belongs to
 * @name: name of the option
 */
static inline struct uci_option *
uci_lookup_option(struct uci_context *ctx, struct uci_section *s, const char *name)
{
	struct uci_element *e = NULL;
	if (uci_lookup_next(ctx, &e, &s->options, name) == 0)
		return uci_to_option(e);
	else
		return NULL;
}

static inline const char *
uci_lookup_option_string(struct uci_context *ctx, struct uci_section *s, const char *name)
{
	struct uci_option *o;

	o = uci_lookup_option(ctx, s, name);
	if (!o || o->type != UCI_TYPE_STRING)
		return NULL;

	return o->v.string;
}

#ifdef __cplusplus
}
#endif

#endif

5.2libubus.h

/*
 * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __LIBUBUS_H
#define __LIBUBUS_H

#include <libubox/avl.h>
#include <libubox/list.h>
#include <libubox/blobmsg.h>
#include <libubox/uloop.h>
#include <stdint.h>
#include "ubusmsg.h"
#include "ubus_common.h"

#define UBUS_MAX_NOTIFY_PEERS	16

struct ubus_context;
struct ubus_msg_src;
struct ubus_object;
struct ubus_request;
struct ubus_request_data;
struct ubus_object_data;
struct ubus_event_handler;
struct ubus_subscriber;
struct ubus_notify_request;

struct ubus_msghdr_buf {
	struct ubus_msghdr hdr;
	struct blob_attr *data;
};

typedef void (*ubus_lookup_handler_t)(struct ubus_context *ctx,
				      struct ubus_object_data *obj,
				      void *priv);
typedef int (*ubus_handler_t)(struct ubus_context *ctx, struct ubus_object *obj,
			      struct ubus_request_data *req,
			      const char *method, struct blob_attr *msg);
typedef void (*ubus_state_handler_t)(struct ubus_context *ctx, struct ubus_object *obj);
typedef void (*ubus_remove_handler_t)(struct ubus_context *ctx,
				      struct ubus_subscriber *obj, uint32_t id);
typedef void (*ubus_event_handler_t)(struct ubus_context *ctx, struct ubus_event_handler *ev,
				     const char *type, struct blob_attr *msg);
typedef void (*ubus_data_handler_t)(struct ubus_request *req,
				    int type, struct blob_attr *msg);
typedef void (*ubus_fd_handler_t)(struct ubus_request *req, int fd);
typedef void (*ubus_complete_handler_t)(struct ubus_request *req, int ret);
typedef void (*ubus_notify_complete_handler_t)(struct ubus_notify_request *req,
					       int idx, int ret);
typedef void (*ubus_connect_handler_t)(struct ubus_context *ctx);

#define UBUS_OBJECT_TYPE(_name, _methods)		\
	{						\
		.name = _name,				\
		.id = 0,				\
		.n_methods = ARRAY_SIZE(_methods),	\
		.methods = _methods			\
	}

#define __UBUS_METHOD_NOARG(_name, _handler)		\
	.name = _name,					\
	.handler = _handler

#define __UBUS_METHOD(_name, _handler, _policy)		\
	__UBUS_METHOD_NOARG(_name, _handler),		\
	.policy = _policy,				\
	.n_policy = ARRAY_SIZE(_policy)

#define UBUS_METHOD(_name, _handler, _policy)		\
	{ __UBUS_METHOD(_name, _handler, _policy) }

#define UBUS_METHOD_MASK(_name, _handler, _policy, _mask) \
	{						\
		__UBUS_METHOD(_name, _handler, _policy),\
		.mask = _mask				\
	}

#define UBUS_METHOD_NOARG(_name, _handler)		\
	{ __UBUS_METHOD_NOARG(_name, _handler) }

struct ubus_method {
	const char *name;
	ubus_handler_t handler;

	unsigned long mask;
	const struct blobmsg_policy *policy;
	int n_policy;
};

struct ubus_object_type {
	const char *name;
	uint32_t id;

	const struct ubus_method *methods;
	int n_methods;
};

struct ubus_object {
	struct avl_node avl;

	const char *name;
	uint32_t id;

	const char *path;
	struct ubus_object_type *type;

	ubus_state_handler_t subscribe_cb;
	bool has_subscribers;

	const struct ubus_method *methods;
	int n_methods;
};

struct ubus_subscriber {
	struct ubus_object obj;

	ubus_handler_t cb;
	ubus_remove_handler_t remove_cb;
};

struct ubus_event_handler {
	struct ubus_object obj;

	ubus_event_handler_t cb;
};

struct ubus_context {
	struct list_head requests;
	struct avl_tree objects;
	struct list_head pending;

	struct uloop_fd sock;
	struct uloop_timeout pending_timer;

	uint32_t local_id;
	uint16_t request_seq;
	int stack_depth;

	void (*connection_lost)(struct ubus_context *ctx);

	struct ubus_msghdr_buf msgbuf;
	uint32_t msgbuf_data_len;
	int msgbuf_reduction_counter;
};

struct ubus_object_data {
	uint32_t id;
	uint32_t type_id;
	const char *path;
	struct blob_attr *signature;
};

struct ubus_request_data {
	uint32_t object;
	uint32_t peer;
	uint16_t seq;

	/* internal use */
	bool deferred;
	int fd;
};

struct ubus_request {
	struct list_head list;

	struct list_head pending;
	int status_code;
	bool status_msg;
	bool blocked;
	bool cancelled;
	bool notify;

	uint32_t peer;
	uint16_t seq;

	ubus_data_handler_t raw_data_cb;
	ubus_data_handler_t data_cb;
	ubus_fd_handler_t fd_cb;
	ubus_complete_handler_t complete_cb;

	struct ubus_context *ctx;
	void *priv;
};

struct ubus_notify_request {
	struct ubus_request req;

	ubus_notify_complete_handler_t status_cb;
	ubus_notify_complete_handler_t complete_cb;

	uint32_t pending;
	uint32_t id[UBUS_MAX_NOTIFY_PEERS + 1];
};

struct ubus_auto_conn {
	struct ubus_context ctx;
	struct uloop_timeout timer;
	const char *path;
	ubus_connect_handler_t cb;
};

struct ubus_context *ubus_connect(const char *path);
void ubus_auto_connect(struct ubus_auto_conn *conn);
int ubus_reconnect(struct ubus_context *ctx, const char *path);
void ubus_free(struct ubus_context *ctx);

const char *ubus_strerror(int error);

static inline void ubus_add_uloop(struct ubus_context *ctx)
{
	uloop_fd_add(&ctx->sock, ULOOP_BLOCKING | ULOOP_READ);
}

/* call this for read events on ctx->sock.fd when not using uloop */
static inline void ubus_handle_event(struct ubus_context *ctx)
{
	ctx->sock.cb(&ctx->sock, ULOOP_READ);
}

/* ----------- raw request handling ----------- */

/* wait for a request to complete and return its status */
int ubus_complete_request(struct ubus_context *ctx, struct ubus_request *req,
			  int timeout);

/* complete a request asynchronously */
void ubus_complete_request_async(struct ubus_context *ctx,
				 struct ubus_request *req);

/* abort an asynchronous request */
void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req);

/* ----------- objects ----------- */

int ubus_lookup(struct ubus_context *ctx, const char *path,
		ubus_lookup_handler_t cb, void *priv);

int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id);

/* make an object visible to remote connections */
int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj);

/* remove the object from the ubus connection */
int ubus_remove_object(struct ubus_context *ctx, struct ubus_object *obj);

/* add a subscriber notifications from another object */
int ubus_register_subscriber(struct ubus_context *ctx, struct ubus_subscriber *obj);

static inline int
ubus_unregister_subscriber(struct ubus_context *ctx, struct ubus_subscriber *obj)
{
	return ubus_remove_object(ctx, &obj->obj);
}

int ubus_subscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id);
int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id);

/* ----------- rpc ----------- */

/* invoke a method on a specific object */
int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method,
		struct blob_attr *msg, ubus_data_handler_t cb, void *priv,
		int timeout);

/* asynchronous version of ubus_invoke() */
int ubus_invoke_async(struct ubus_context *ctx, uint32_t obj, const char *method,
		      struct blob_attr *msg, struct ubus_request *req);

/* send a reply to an incoming object method call */
int ubus_send_reply(struct ubus_context *ctx, struct ubus_request_data *req,
		    struct blob_attr *msg);

static inline void ubus_defer_request(struct ubus_context *ctx,
				      struct ubus_request_data *req,
				      struct ubus_request_data *new_req)
{
    memcpy(new_req, req, sizeof(*req));
    req->deferred = true;
}

static inline void ubus_request_set_fd(struct ubus_context *ctx,
				       struct ubus_request_data *req, int fd)
{
    req->fd = fd;
}

void ubus_complete_deferred_request(struct ubus_context *ctx,
				    struct ubus_request_data *req, int ret);

/*
 * send a notification to all subscribers of an object
 * if timeout < 0, no reply is expected from subscribers
 */
int ubus_notify(struct ubus_context *ctx, struct ubus_object *obj,
		const char *type, struct blob_attr *msg, int timeout);

int ubus_notify_async(struct ubus_context *ctx, struct ubus_object *obj,
		      const char *type, struct blob_attr *msg,
		      struct ubus_notify_request *req);


/* ----------- events ----------- */

int ubus_send_event(struct ubus_context *ctx, const char *id,
		    struct blob_attr *data);

int ubus_register_event_handler(struct ubus_context *ctx,
				struct ubus_event_handler *ev,
				const char *pattern);

static inline int ubus_unregister_event_handler(struct ubus_context *ctx,
						struct ubus_event_handler *ev)
{
    return ubus_remove_object(ctx, &ev->obj);
}

#endif

5.3ubusd_obj.h

/*
 * Copyright (C) 2011 Felix Fietkau <nbd@openwrt.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __UBUSD_OBJ_H
#define __UBUSD_OBJ_H

#include "ubusd_id.h"

extern struct avl_tree obj_types;
extern struct avl_tree objects;
extern struct avl_tree path;

struct ubus_client;
struct ubus_msg_buf;

struct ubus_object_type {
	struct ubus_id id;
	int refcount;
	struct list_head methods;
};

struct ubus_method {
	struct list_head list;
	const char *name;
	struct blob_attr data[];
};

struct ubus_subscription {
	struct list_head list, target_list;
	struct ubus_object *subscriber, *target;
};

struct ubus_object {
	struct ubus_id id;
	struct list_head list;

	struct list_head events;

	struct list_head subscribers, target_list;

	struct ubus_object_type *type;
	struct avl_node path;

	struct ubus_client *client;
	int (*recv_msg)(struct ubus_client *client, const char *method, struct blob_attr *msg);

	int event_seen;
	unsigned int invoke_seq;
};

struct ubus_object *ubusd_create_object(struct ubus_client *cl, struct blob_attr **attr);
struct ubus_object *ubusd_create_object_internal(struct ubus_object_type *type, uint32_t id);
void ubusd_free_object(struct ubus_object *obj);

static inline struct ubus_object *ubusd_find_object(uint32_t objid)
{
	struct ubus_object *obj;
	struct ubus_id *id;

	id = ubus_find_id(&objects, objid);
	if (!id)
		return NULL;

	obj = container_of(id, struct ubus_object, id);
	return obj;
}

void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target);
void ubus_unsubscribe(struct ubus_subscription *s);
void ubus_notify_unsubscribe(struct ubus_subscription *s);
void ubus_notify_subscription(struct ubus_object *obj);

#endif

5.4json.h


#include <stdio.h>
#include "cfg_json_interface.h"

/*
 * 函数功能:创建一个json对象
 */
ZLINK_jsonObj *ZLINK_JSON_NewObject()
{
    return json_object_new_object();
}

/*
 * 函数功能:创建一个json对象数组
 */
ZLINK_jsonObj *ZLINK_JSON_NewObjectArray()
{
    return json_object_new_array();
}

/*
 * 函数功能:销毁json对象
 */
void ZLINK_JSON_DestroyObject(json_object *obj)
{
    if (obj == NULL) {
        return;
    }
    json_object_put(obj);
    return;
}

/*
 * 函数功能:增加json对象
 */
int ZLINK_JSON_AddObject(ZLINK_jsonObj *obj, const char *key, ZLINK_jsonObj *val)
{
    if (obj == NULL || key == NULL || val == NULL) {
        return ZLINK_FAILED;
    }
    return json_object_object_add(obj, key, val);
}

/*
 * 函数功能:json对象中添加string的元素
 */
ZLINK_jsonObj *ZLINK_JSON_AddString(const char *str)
{
    if (str == NULL) {
        return NULL;
    }
    return json_object_new_string(str);
}

/*
 * 函数功能:json对象中添加int的元素
 */
ZLINK_jsonObj *ZLINK_JSON_AddInt(int i)
{
    return json_object_new_int(i);
}

/*
 * 函数功能:获取json对象
 */
ZLINK_jsonObj *ZLINK_JSON_GetObject(ZLINK_jsonObj *obj, const char *key)
{
    if (obj == NULL || key == NULL) {
        return NULL;
    }
    return json_object_object_get(obj, key);
}

/*
 * 函数功能:json对象中获取string的元素
 */
const char * ZLINK_JSON_GetString(ZLINK_jsonObj *obj)
{
    if (obj == NULL) {
        return NULL;
    }
    return json_object_get_string(obj);
}

/*
 * 函数功能:json对象中获取int的元素
 */
int ZLINK_JSON_GetInt(ZLINK_jsonObj *obj)
{
    if (obj == NULL) {
        return ZLINK_FAILED;
    }
    return json_object_get_int(obj);
}

ZLINK_jsonObj *ZLINK_JSON_StringToObject(const char *str)
{
    if (str == NULL) {
        return NULL;
    }
    return json_tokener_parse(str);
}

/*
 * 函数功能:将json obj转换为字符串
 */
const char *ZLINK_JSON_ObjectToString(ZLINK_jsonObj *obj)
{
    if (obj == NULL) {
        return NULL;
    }
    return json_object_to_json_string(obj);
}

/*
 * 函数功能:计算json数组的长度
 */
int ZLINK_JSON_ObjectArrayLength(ZLINK_jsonObj *array)
{
    if (array == NULL) {
        return ZLINK_FAILED;
    }
    return json_object_array_length(array);
}

5.5blobmsg.h


16  #ifndef __BLOBMSG_H
17  #define __BLOBMSG_H
18  
19  #include <stdarg.h>
20  #include "blob.h"
21  
22  #define BLOBMSG_ALIGN	2
23  #define BLOBMSG_PADDING(len) (((len) + (1 << BLOBMSG_ALIGN) - 1) & ~((1 << BLOBMSG_ALIGN) - 1))
24  
25  enum blobmsg_type {
26  	BLOBMSG_TYPE_UNSPEC,
27  	BLOBMSG_TYPE_ARRAY,
28  	BLOBMSG_TYPE_TABLE,
29  	BLOBMSG_TYPE_STRING,
30  	BLOBMSG_TYPE_INT64,
31  	BLOBMSG_TYPE_INT32,
32  	BLOBMSG_TYPE_INT16,
33  	BLOBMSG_TYPE_INT8,
34  	__BLOBMSG_TYPE_LAST,
35  	BLOBMSG_TYPE_LAST = __BLOBMSG_TYPE_LAST - 1,
36  	BLOBMSG_TYPE_BOOL = BLOBMSG_TYPE_INT8,
37  };
38  
39  struct blobmsg_hdr {
40  	uint16_t namelen;
41  	uint8_t name[];
42  } __packed;
43  
44  struct blobmsg_policy {
45  	const char *name;
46  	enum blobmsg_type type;
47  };
48  
49  static inline int blobmsg_hdrlen(unsigned int namelen)
50  {
51  	return BLOBMSG_PADDING(sizeof(struct blobmsg_hdr) + namelen + 1);
52  }
53  
54  static inline void blobmsg_clear_name(struct blob_attr *attr)
55  {
56  	struct blobmsg_hdr *hdr = (struct blobmsg_hdr *) blob_data(attr);
57  	hdr->name[0] = 0;
58  }
59  
60  static inline const char *blobmsg_name(const struct blob_attr *attr)
61  {
62  	struct blobmsg_hdr *hdr = (struct blobmsg_hdr *) blob_data(attr);
63  	return (const char *) hdr->name;
64  }
65  
66  static inline int blobmsg_type(const struct blob_attr *attr)
67  {
68  	return blob_id(attr);
69  }
70  
71  static inline void *blobmsg_data(const struct blob_attr *attr)
72  {
73  	struct blobmsg_hdr *hdr = (struct blobmsg_hdr *) blob_data(attr);
74  	char *data = (char *) blob_data(attr);
75  
76  	if (blob_is_extended(attr))
77  		data += blobmsg_hdrlen(be16_to_cpu(hdr->namelen));
78  
79  	return data;
80  }
81  
82  static inline int blobmsg_data_len(const struct blob_attr *attr)
83  {
84  	uint8_t *start, *end;
85  
86  	start = (uint8_t *) blob_data(attr);
87  	end = (uint8_t *) blobmsg_data(attr);
88  
89  	return blob_len(attr) - (end - start);
90  }
91  
92  static inline int blobmsg_len(const struct blob_attr *attr)
93  {
94  	return blobmsg_data_len(attr);
95  }
96  
97  bool blobmsg_check_attr(const struct blob_attr *attr, bool name);
98  bool blobmsg_check_attr_list(const struct blob_attr *attr, int type);
99  
100  /*
101   * blobmsg_check_array: validate array/table and return size
102   *
103   * Checks if all elements of an array or table are valid and have
104   * the specified type. Returns the number of elements in the array
105   */
106  int blobmsg_check_array(const struct blob_attr *attr, int type);
107  
108  int blobmsg_parse(const struct blobmsg_policy *policy, int policy_len,
109                    struct blob_attr **tb, void *data, unsigned int len);
110  int blobmsg_parse_array(const struct blobmsg_policy *policy, int policy_len,
111  			struct blob_attr **tb, void *data, unsigned int len);
112  
113  int blobmsg_add_field(struct blob_buf *buf, int type, const char *name,
114                        const void *data, unsigned int len);
115  
116  static inline int
117  blobmsg_add_u8(struct blob_buf *buf, const char *name, uint8_t val)
118  {
119  	return blobmsg_add_field(buf, BLOBMSG_TYPE_INT8, name, &val, 1);
120  }
121  
122  static inline int
123  blobmsg_add_u16(struct blob_buf *buf, const char *name, uint16_t val)
124  {
125  	val = cpu_to_be16(val);
126  	return blobmsg_add_field(buf, BLOBMSG_TYPE_INT16, name, &val, 2);
127  }
128  
129  static inline int
130  blobmsg_add_u32(struct blob_buf *buf, const char *name, uint32_t val)
131  {
132  	val = cpu_to_be32(val);
133  	return blobmsg_add_field(buf, BLOBMSG_TYPE_INT32, name, &val, 4);
134  }
135  
136  static inline int
137  blobmsg_add_u64(struct blob_buf *buf, const char *name, uint64_t val)
138  {
139  	val = cpu_to_be64(val);
140  	return blobmsg_add_field(buf, BLOBMSG_TYPE_INT64, name, &val, 8);
141  }
142  
143  static inline int
144  blobmsg_add_string(struct blob_buf *buf, const char *name, const char *string)
145  {
146  	return blobmsg_add_field(buf, BLOBMSG_TYPE_STRING, name, string, strlen(string) + 1);
147  }
148  
149  static inline int
150  blobmsg_add_blob(struct blob_buf *buf, struct blob_attr *attr)
151  {
152  	return blobmsg_add_field(buf, blobmsg_type(attr), blobmsg_name(attr),
153  				 blobmsg_data(attr), blobmsg_data_len(attr));
154  }
155  
156  void *blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array);
157  
158  static inline void *
159  blobmsg_open_array(struct blob_buf *buf, const char *name)
160  {
161  	return blobmsg_open_nested(buf, name, true);
162  }
163  
164  static inline void *
165  blobmsg_open_table(struct blob_buf *buf, const char *name)
166  {
167  	return blobmsg_open_nested(buf, name, false);
168  }
169  
170  static inline void
171  blobmsg_close_array(struct blob_buf *buf, void *cookie)
172  {
173  	blob_nest_end(buf, cookie);
174  }
175  
176  static inline void
177  blobmsg_close_table(struct blob_buf *buf, void *cookie)
178  {
179  	blob_nest_end(buf, cookie);
180  }
181  
182  static inline int blobmsg_buf_init(struct blob_buf *buf)
183  {
184  	return blob_buf_init(buf, BLOBMSG_TYPE_TABLE);
185  }
186  
187  static inline uint8_t blobmsg_get_u8(struct blob_attr *attr)
188  {
189  	return *(uint8_t *) blobmsg_data(attr);
190  }
191  
192  static inline bool blobmsg_get_bool(struct blob_attr *attr)
193  {
194  	return *(uint8_t *) blobmsg_data(attr);
195  }
196  
197  static inline uint16_t blobmsg_get_u16(struct blob_attr *attr)
198  {
199  	return be16_to_cpu(*(uint16_t *) blobmsg_data(attr));
200  }
201  
202  static inline uint32_t blobmsg_get_u32(struct blob_attr *attr)
203  {
204  	return be32_to_cpu(*(uint32_t *) blobmsg_data(attr));
205  }
206  
207  static inline uint64_t blobmsg_get_u64(struct blob_attr *attr)
208  {
209  	uint32_t *ptr = (uint32_t *) blobmsg_data(attr);
210  	uint64_t tmp = ((uint64_t) be32_to_cpu(ptr[0])) << 32;
211  	tmp |= be32_to_cpu(ptr[1]);
212  	return tmp;
213  }
214  
215  static inline char *blobmsg_get_string(struct blob_attr *attr)
216  {
217  	if (!attr)
218  		return NULL;
219  
220  	return (char *) blobmsg_data(attr);
221  }
222  
223  void *blobmsg_alloc_string_buffer(struct blob_buf *buf, const char *name, unsigned int maxlen);
224  void *blobmsg_realloc_string_buffer(struct blob_buf *buf, unsigned int maxlen);
225  void blobmsg_add_string_buffer(struct blob_buf *buf);
226  
227  void blobmsg_vprintf(struct blob_buf *buf, const char *name, const char *format, va_list arg);
228  void blobmsg_printf(struct blob_buf *buf, const char *name, const char *format, ...)
229       __attribute__((format(printf, 3, 4)));
230  
231  
232  /* blobmsg to json formatting */
233  
234  #define blobmsg_for_each_attr(pos, attr, rem) \
235  	for (rem = attr ? blobmsg_data_len(attr) : 0, \
236  	     pos = attr ? blobmsg_data(attr) : 0; \
237  	     rem > 0 && (blob_pad_len(pos) <= rem) && \
238  	     (blob_pad_len(pos) >= sizeof(struct blob_attr)); \
239  	     rem -= blob_pad_len(pos), pos = blob_next(pos))
240  
241  #endif

5.6blob.h

19  #ifndef _BLOB_H__
20  #define _BLOB_H__
21  
22  #include <stdbool.h>
23  #include <stdlib.h>
24  #include <stdint.h>
25  #include <string.h>
26  #include <stdio.h>
27  #include <errno.h>
28  
29  #include "utils.h"
30  
31  #define BLOB_COOKIE		0x01234567
32  
33  enum {
34  	BLOB_ATTR_UNSPEC,
35  	BLOB_ATTR_NESTED,
36  	BLOB_ATTR_BINARY,
37  	BLOB_ATTR_STRING,
38  	BLOB_ATTR_INT8,
39  	BLOB_ATTR_INT16,
40  	BLOB_ATTR_INT32,
41  	BLOB_ATTR_INT64,
42  	BLOB_ATTR_LAST
43  };
44  
45  #define BLOB_ATTR_ID_MASK  0x7f000000
46  #define BLOB_ATTR_ID_SHIFT 24
47  #define BLOB_ATTR_LEN_MASK 0x00ffffff
48  #define BLOB_ATTR_ALIGN    4
49  #define BLOB_ATTR_EXTENDED 0x80000000
50  
51  struct blob_attr {
52  	uint32_t id_len;
53  	char data[];
54  } __packed;
55  
56  struct blob_attr_info {
57  	unsigned int type;
58  	unsigned int minlen;
59  	unsigned int maxlen;
60  	bool (*validate)(const struct blob_attr_info *, struct blob_attr *);
61  };
62  
63  struct blob_buf {
64  	struct blob_attr *head;
65  	bool (*grow)(struct blob_buf *buf, int minlen);
66  	int buflen;
67  	void *buf;
68  };
69  
70  /*
71   * blob_data: returns the data pointer for an attribute
72   */
73  static inline void *
74  blob_data(const struct blob_attr *attr)
75  {
76  	return (void *) attr->data;
77  }
78  
79  /*
80   * blob_id: returns the id of an attribute
81   */
82  static inline unsigned int
83  blob_id(const struct blob_attr *attr)
84  {
85  	int id = (be32_to_cpu(attr->id_len) & BLOB_ATTR_ID_MASK) >> BLOB_ATTR_ID_SHIFT;
86  	return id;
87  }
88  
89  static inline bool
90  blob_is_extended(const struct blob_attr *attr)
91  {
92  	return !!(attr->id_len & cpu_to_be32(BLOB_ATTR_EXTENDED));
93  }
94  
95  /*
96   * blob_len: returns the length of the attribute's payload
97   */
98  static inline unsigned int
99  blob_len(const struct blob_attr *attr)
100  {
101  	return (be32_to_cpu(attr->id_len) & BLOB_ATTR_LEN_MASK) - sizeof(struct blob_attr);
102  }
103  
104  /*
105   * blob_raw_len: returns the complete length of an attribute (including the header)
106   */
107  static inline unsigned int
108  blob_raw_len(const struct blob_attr *attr)
109  {
110  	return blob_len(attr) + sizeof(struct blob_attr);
111  }
112  
113  /*
114   * blob_pad_len: returns the padded length of an attribute (including the header)
115   */
116  static inline unsigned int
117  blob_pad_len(const struct blob_attr *attr)
118  {
119  	unsigned int len = blob_raw_len(attr);
120  	len = (len + BLOB_ATTR_ALIGN - 1) & ~(BLOB_ATTR_ALIGN - 1);
121  	return len;
122  }
123  
124  static inline uint8_t
125  blob_get_u8(const struct blob_attr *attr)
126  {
127  	return *((uint8_t *) attr->data);
128  }
129  
130  static inline uint16_t
131  blob_get_u16(const struct blob_attr *attr)
132  {
133  	uint16_t *tmp = (uint16_t*)attr->data;
134  	return be16_to_cpu(*tmp);
135  }
136  
137  static inline uint32_t
138  blob_get_u32(const struct blob_attr *attr)
139  {
140  	uint32_t *tmp = (uint32_t*)attr->data;
141  	return be32_to_cpu(*tmp);
142  }
143  
144  static inline uint64_t
145  blob_get_u64(const struct blob_attr *attr)
146  {
147  	uint32_t *ptr = (uint32_t *) blob_data(attr);
148  	uint64_t tmp = ((uint64_t) be32_to_cpu(ptr[0])) << 32;
149  	tmp |= be32_to_cpu(ptr[1]);
150  	return tmp;
151  }
152  
153  static inline int8_t
154  blob_get_int8(const struct blob_attr *attr)
155  {
156  	return blob_get_u8(attr);
157  }
158  
159  static inline int16_t
160  blob_get_int16(const struct blob_attr *attr)
161  {
162  	return blob_get_u16(attr);
163  }
164  
165  static inline int32_t
166  blob_get_int32(const struct blob_attr *attr)
167  {
168  	return blob_get_u32(attr);
169  }
170  
171  static inline int64_t
172  blob_get_int64(const struct blob_attr *attr)
173  {
174  	return blob_get_u64(attr);
175  }
176  
177  static inline const char *
178  blob_get_string(const struct blob_attr *attr)
179  {
180  	return attr->data;
181  }
182  
183  static inline struct blob_attr *
184  blob_next(const struct blob_attr *attr)
185  {
186  	return (struct blob_attr *) ((char *) attr + blob_pad_len(attr));
187  }
188  
189  extern void blob_fill_pad(struct blob_attr *attr);
190  extern void blob_set_raw_len(struct blob_attr *attr, unsigned int len);
191  extern bool blob_attr_equal(const struct blob_attr *a1, const struct blob_attr *a2);
192  extern int blob_buf_init(struct blob_buf *buf, int id);
193  extern void blob_buf_free(struct blob_buf *buf);
194  extern bool blob_buf_grow(struct blob_buf *buf, int required);
195  extern struct blob_attr *blob_new(struct blob_buf *buf, int id, int payload);
196  extern void *blob_nest_start(struct blob_buf *buf, int id);
197  extern void blob_nest_end(struct blob_buf *buf, void *cookie);
198  extern struct blob_attr *blob_put(struct blob_buf *buf, int id, const void *ptr, unsigned int len);
199  extern bool blob_check_type(const void *ptr, unsigned int len, int type);
200  extern int blob_parse(struct blob_attr *attr, struct blob_attr **data, const struct blob_attr_info *info, int max);
201  extern struct blob_attr *blob_memdup(struct blob_attr *attr);
202  extern struct blob_attr *blob_put_raw(struct blob_buf *buf, const void *ptr, unsigned int len);
203  
204  static inline struct blob_attr *
205  blob_put_string(struct blob_buf *buf, int id, const char *str)
206  {
207  	return blob_put(buf, id, str, strlen(str) + 1);
208  }
209  
210  static inline struct blob_attr *
211  blob_put_u8(struct blob_buf *buf, int id, uint8_t val)
212  {
213  	return blob_put(buf, id, &val, sizeof(val));
214  }
215  
216  static inline struct blob_attr *
217  blob_put_u16(struct blob_buf *buf, int id, uint16_t val)
218  {
219  	val = cpu_to_be16(val);
220  	return blob_put(buf, id, &val, sizeof(val));
221  }
222  
223  static inline struct blob_attr *
224  blob_put_u32(struct blob_buf *buf, int id, uint32_t val)
225  {
226  	val = cpu_to_be32(val);
227  	return blob_put(buf, id, &val, sizeof(val));
228  }
229  
230  static inline struct blob_attr *
231  blob_put_u64(struct blob_buf *buf, int id, uint64_t val)
232  {
233  	val = cpu_to_be64(val);
234  	return blob_put(buf, id, &val, sizeof(val));
235  }
236  
237  #define blob_put_int8	blob_put_u8
238  #define blob_put_int16	blob_put_u16
239  #define blob_put_int32	blob_put_u32
240  #define blob_put_int64	blob_put_u64
241  
242  #define __blob_for_each_attr(pos, attr, rem) \
243  	for (pos = (void *) attr; \
244  	     rem > 0 && (blob_pad_len(pos) <= rem) && \
245  	     (blob_pad_len(pos) >= sizeof(struct blob_attr)); \
246  	     rem -= blob_pad_len(pos), pos = blob_next(pos))
247  
248  
249  #define blob_for_each_attr(pos, attr, rem) \
250  	for (rem = attr ? blob_len(attr) : 0, \
251  	     pos = attr ? blob_data(attr) : 0; \
252  	     rem > 0 && (blob_pad_len(pos) <= rem) && \
253  	     (blob_pad_len(pos) >= sizeof(struct blob_attr)); \
254  	     rem -= blob_pad_len(pos), pos = blob_next(pos))
255  
256  
257  #endif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值