ubus [1] - ubusd

ubusd

數據結構

struct ubus_msg_buf {
    uint32_t refcount; /* ~0: uses external data buffer */
    struct ubus_msghdr hdr;
    struct blob_attr *data;
    int fd;            /** 發送msg端進程傳過來的fd,用於UBUS_MSG_STATUS消息 */
    int len;
};

struct ubus_client {
    struct ubus_id id;
    struct uloop_fd sock;

    struct list_head objects;

    struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG];
    /**
     * txq_cur  - tx隊列未處理頭結點
     * txq_tail - tx隊列可用結點頭
     * txq_ofs  - 當前結點已發送offset
     */
    unsigned int txq_cur, txq_tail, txq_ofs;

    struct ubus_msg_buf *pending_msg;
    int pending_msg_offset;
    int pending_msg_fd;     /** 對端進程傳過來的fd */
    struct {
        struct ubus_msghdr hdr;
        struct blob_attr data;
    } hdrbuf;                /** 報文格式頭 */
};

struct ubus_path {
    struct list_head list;
    const char name[];
};

處理流程

ubusd啓動時自動調用初始化函數ubusd_obj_init(void)分別建立objectsobj_typespath三個AVL tree頭節點,同時調用ubusd_event_init()函數初始化patterns AVL tree頭節點,建立event_obj全局事件對象,對象ID等於1(UBUS_SYSTEM_OBJECT_EVENT)node

Server_fd監聽函數server_cb註冊到uloop中數據結構

  • 新client鏈接時
    建立struct ubus_client數據結構,初始化client fd回調函數client_cb,並加入到全局clients avl_tree中進行維護,最後把此client註冊到uloop中函數

  • 收到client報文時
    若是發送隊列中存在數據,則儘可能把隊列中全部內容發出
    先收取報文頭部數據,以肯定整個報文內容長度,報文頭部數據結構以下oop

struct {
        struct ubus_msghdr hdr;
        struct blob_attr data;
    } hdrbuf;
struct ubus_msghdr {
    uint8_t version;
    uint8_t type;
    uint16_t seq;
    uint32_t peer;
} __packetdata;
struct blob_attr {
    uint32_t id_len;
    char data[];
} __packed;

收取整個報文內容,存放到struct ubus_msg_buf結構中
調用ubusd_proto_receive_message()函數處理報文內容,此函數根據hdr.type在註冊的handlers中查詢對應的函數,具體請看ubusd_proto說明ui


ubusd_proto

消息處理

消息類型 處理函數
UBUS_MSG_PING ubusd_send_pong
UBUS_MSG_ADD_OBJECT ubusd_handle_add_object
UBUS_MSG_REMOVE_OBJECT ubusd_handle_remove_object
UBUS_MSG_LOOKUP ubusd_handle_lookup
UBUS_MSG_INVOKE ubusd_handle_invoke
UBUS_MSG_STATUS ubusd_handle_response
UBUS_MSG_DATA ubusd_handle_response
UBUS_MSG_SUBSCRIBE ubusd_handle_add_watch
UBUS_MSG_UNSUBSCRIBE ubusd_handle_remove_watch
UBUS_MSG_NOTIFY ubusd_handle_notify

UBUS_MSG_PING

保活探測報文,收到後迴應一個類型爲UBUS_MSG_DATA的報文便可code

UBUS_MSG_ADD_OBJECT

建立內部object,迴應一個類型爲UBUS_MSG_DATA的報文,報文內容有由ubusd生成的UBUS_ATTR_OBJIDserver

UBUS_MSG_REMOVE_OBJECT

刪除內部object,根據請求報文UBUS_ATTR_OBJID查找對應的內容object,若是存在且object建立者等於刪除請求者,則刪除此object,迴應一個類型爲UBUS_MSG_DATA的報文,報文內容有刪除object的UBUS_ATTR_OBJID對象

UBUS_MSG_LOOKUP

查詢object,根據請求報文UBUS_ATTR_OBJPATH查找對應的object,使用ubusd_send_obj()函數把查詢出object內容迴應給查詢請求者接口

UBUS_MSG_INVOKE

執行object,根據請求報文UBUS_ATTR_OBJID查找對應的object,若是object爲ubusd本地對象(event_object)則由本地對象處理,不然使用ubusd_forward_invoke()函數把消息轉發給object擁有者,消息類型爲UBUS_MSG_INVOKE隊列

UBUS_MSG_STATUS

處理結果狀態,把結果轉發給請求者

UBUS_MSG_DATA

同UBUS_MSG_STATUS

UBUS_MSG_NOTIFY

通知全部訂閱者,使用ubusd_forward_invoke()函數通知訂閱請求者全部訂閱者

UBUS_MSG_SUBSCRIBE

訂閱object,使用ubus_subscribe()函數訂閱指定object

UBUS_MSG_UNSUBSCRIBE

退訂object,使用ubus_unsubscribe()函數退訂全部已訂閱的object


ubusd_event

數據結構

struct event_source {
    struct list_head list;     /** object結構中events隊列 */
    struct ubus_object *obj;   /** 指向事件object實體 */
    struct avl_node avl;       /** patterns全局avl tree隊列 */
    bool partial;
};

處理流程

  • 收到事件處理報文
  • Register註冊某個object事件,使用ubusd_alloc_event_pattern()函數建立事件對象並加入到全局patterns隊列中
  • 註冊報文內容
static struct blobmsg_policy evr_policy[] = {
    [EVREG_PATTERN] = { .name = "pattern", .type = BLOBMSG_TYPE_STRING },
    [EVREG_OBJECT] = { .name = "object", .type = BLOBMSG_TYPE_INT32 },
};

Send轉發某個事件內容,使用ubusd_forward_event()函數把指定事件內容轉發給此事件所屬的object擁有者
事件報文內容

static struct blobmsg_policy ev_policy[] = {
    [EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
    [EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
};

對外接口

提供ubusd_send_obj_event()接口發佈"ubus.object.add"和"ubus.object.remove"事件


ubusd_id

數據結構

struct ubus_id {
    struct avl_node avl;
    uint32_t id;
};

接口說明

初始/銷燬

void ubus_init_id_tree(struct avl_tree *tree);
/**
 * @param dup - 容許存在相同結點
 */
void ubus_init_string_tree(struct avl_tree *tree, bool dup);
static inline void ubus_free_id(struct avl_tree *tree, struct ubus_id *id)

增長

/**
 * 添加新ubus_id到val樹中
 *
 * @param tree - val樹根結點
 * @param id   - 新ubus_id
 * @param val  - 新ubus_id值,若是爲0則表示自動隨機生成
 * @return       true - 成功;false - 失敗
 */
bool ubus_alloc_id(struct avl_tree *tree, struct ubus_id *id, uint32_t val)

查詢

static inline struct ubus_id *ubus_find_id(struct avl_tree *tree, uint32_t id)

ubusd_object

數據結構

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;  /** 事件鏈表頭 */

    /**
     * subscribers - 被哪些對象訂閱鏈表頭
     * target_list - 已訂閱哪些對象鏈表頭
     */
    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;
};

接口說明

建立/銷燬

/**
 * 建立新ubus_object
 *
 * @param attr - UBUS_ATTR_OBJTYPE UBUS_ATTR_SIGNATURE UBUS_ATTR_OBJPATH
 */
struct ubus_object *ubusd_create_object(struct ubus_client *cl, 
                                        struct blob_attr **attr);
/**
 * 建立新ubus_object
 */
struct ubus_object *ubusd_create_object_internal(struct ubus_object_type *type, 
                                                uint32_t id);
/**
 * 銷燬ubus_object
 */
void ubusd_free_object(struct ubus_object *obj);

獲取對象

static inline struct ubus_object *ubusd_find_object(uint32_t objid);

訂閱/退訂對象

/**
 * obj訂閱target 
 *
 * @param obj - 訂閱者對象
 * @param target - 被訂閱對象
 */
void ubus_subscribe(struct ubus_object *obj, struct ubus_object *target);

/**
 * 退訂
 */
void ubus_unsubscribe(struct ubus_subscription *s);
相關文章
相關標籤/搜索