I know only the somehow generic wiki pages of OpenWrt and looked mostly at the sources:

https://git.openwrt.org/?p=project/ubus.git;a=blob;f=libubus.h

https://git.openwrt.org/?p=project/libubox.git;a=blob;f=blobmsg_json.c

There is also an example for a client in the tree. Currently I have a working approach,

but I am not sure I am doing it right.


The following program is a small example that extracts all local IPs from the data that the

cli would report for:

          ubus call network.interface.lan status

The first functions are quite generic, the callback does the custom work.

(If it helps, you can use it as the included libs allow it,

I consider my parts as public domain: CC0)


g++ -Os -Wall -Werror -Wextra --std=c++17 -g3 -lubus -lubox

DEPENDS:=+libubus +libubox +libstdcpp

// ----------------------------------------- main.cpp -------------------------------------------------

// ubus_traverse(...) walks the msg tree and processes values for matching keys: //    msg = message that ubus sent to a callback function set up by ubus_invoke. //    process = function to which values are send if all the following keys match. //    key, ... keys = match the keys of the msg tree in the given order; we are at //        the end if there is only one key left, do nothing if there is none. //    (works if the number of keys is known at compile time, else use valist ...)

void ubus_traverse(const blob_attr * msg, function<void(const void * val)> process)
{}

template<class T, class ... Types>

void ubus_traverse(const blob_attr * msg, function<void(const void * val)> process,

                   T key, Types ... keys)
{
    size_t len;
    blob_attr * pos;
    blobmsg_for_each_attr(pos, msg, len) {
        const char * name = blobmsg_name(pos);
        if (strcmp(name, key) != 0) { continue; }
        switch (blob_id(pos)) {
            case BLOBMSG_TYPE_TABLE: [[fallthrough]]
            case BLOBMSG_TYPE_ARRAY: ubus_traverse(pos, process, keys...);
            break;
            default: if (sizeof...(keys)==0) { process(blobmsg_data(pos)); }
        }
    }
}


static int ubus_call(const char * path, const char * method,
                     ubus_data_handler_t callback)
{
    ubus_context * ctx = ubus_connect(NULL);
    if (ctx==NULL) { return -1; }
    uint32_t id;
    int ret = ubus_lookup_id(ctx, path, &id);
    if (ret==0) {
        static blob_buf req;
        blob_buf_init(&req, 0);
        int timeout = 200;
        ret = ubus_invoke(ctx, id, method, req.head, callback, NULL, timeout);
    }
    if (ctx) { ubus_free(ctx); }
    return ret;
}


void ip_callback(ubus_request * req, int type, blob_attr * msg)
{
    if (!msg) { return; }
    string ips = "";
    auto add_ip = [&ips] (const void * val) -> void
    {
        ips += (char *)val;
        ips += " ";
    };
    ubus_traverse(msg, add_ip, "ipv4-address", "", "address");
    ubus_traverse(msg, add_ip, "ipv6-address", "", "address");
    cout<<"IPs: "<<ips<<endl;
}


int main(int argc, char * argv[]) {
    ubus_call("network.interface.lan", "status", ip_callback);
    return 0;
}


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to