OpenWrt UBUS

What is UBUS?

Ubus is an RPC tool of OpenWRT, a micro system bus architecture. The aim of Ubus is to provide system-level Inter-process Communication(IPC) for various background processes and applications. Ubus is basically consistent with D-Bus in the design conception, providing system-level bus function. In order to be compatible with constrained environment says embedded systems, ubus reduced memory footprint.

  • Provide various daemons and applications with IPC(Inter-process Communication) service.
  • Work as a broker, forward messages between related application(s) in different ways.
  • Several tools are invented for accessing UBUS
    • libubus: a library for software to access UBUS.
    • Cmd-line ubus tool.
    • Ubus Lua module

IPC

Inter-process Communication refers to mechanism allowing processes to manage shared data. There are different approaches to IPC tailored to different software requirements, says performance, modularity, network bandwidth and latency.
Examples of IPC method:

  • File
  • Signal
  • Socket / Unix domain Socket
  • Shared memory

Most of IPC methods use client-server model to share data between processes.

Connection model of client-server model







%0


cluster2

Client-server Model(m:n)


cluster1

Client-server Model(1:1)



s1

Process 1



s2

Process 2



s1->s2





d

Process 3



s1->d





e

Process 4



s1->e





f

Process 5



s1->f





s2->s1





s2->e





s2->f





g

Process 6



s2->g





d->s1





d->e





d->f





e->s1





e->s2





e->d





f->s1





f->s2





f->d





g->s2





a

Process 1
Server



b

Process 2
Client



a->b


Response



b->a


Request



While there are m servers, and each server has nk clients. The number of IPC connections in client/server model is:
k=1mnk

Connection model of UBUS

Ubus uses the broker pattern as its architecture. There are three components to perform IPC through ubus.

  1. ubus daemon: Broker/middleman between ubus server object and ubus client object, manages registration, and forwards messages between server and client object.
  2. ubus server object: Usually interface/daemon of some software. Registers to ubus daemon with methods provided for client. Server objects and the methods registered can be looked up and called by client objects.
  3. ubus client object: Caller of server objects and methods.






%0



ubus

                                                            Ubusd                                                            



p1

Process 1
Server Object



ubus->p1





p2

Process 2
Server Object



ubus->p2





p3

Process 3
Client Object



ubus->p3





p4

Process 4
Client Object



ubus->p4





p5

Process 5
Client Object



ubus->p5





p6

Process 6
Client Object



ubus->p6





p1->ubus





p2->ubus





p3->ubus





p4->ubus





p5->ubus





p6->ubus





In this architecture, the number of connections is the number of processes, including both service "clients" and "servers", which is much less than IPC implementations under client/server model.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Roles in UBUS

There are different roles in Ubus IPC processes.

  1. Object
    • Process registered to ubusd, including service and service callers.
  2. Method
    • Procedure provdied by objects. Object can provide various methods as a server.
  3. Data
    • Information in JSON format carried by requests or replies.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

Relations of object, method and data under UBUS.

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

List of object on Ubus, methods and related data signature of 'system'.

  1. Subscriber
    • Object subscribed to target service object. Subscribers will be notified once target service object sends a notification to ubusd.
  2. Event
    • Event in Ubus is identified by a string called "event pattern". Event can be registered by object. Object can send data to ubusd with event pattern.
  3. Event Registrant
    • Object registered to event with "event pattern". Ubusd forwards data to event registrant once message with matched "event pattern" is received.

Data format of UBUS - JSON

Ubus uses JSON as data format to call object, method and respond to request.

https://www.json.org/json-en.html

Here is an status example in JSON format. We call the method status of object network.interface.wan3 with null message '{}'.

root@ugwcpe:/# ubus call network.interface.wan3 status { "up": true, "pending": false, "available": true, "autostart": true, "dynamic": false, "uptime": 5, "l3_device": "eth1_wan3", "proto": "dhcp", "device": "eth1_wan3", "updated": [ "addresses", "routes", "data" ], "metric": 0, "dns_metric": 0, "delegation": true, "ipv4-address": [ { "address": "192.168.121.101", "mask": 24 } ], "ipv6-address": [ ], "ipv6-prefix": [ ], "ipv6-prefix-assignment": [ ], "route": [ { "target": "0.0.0.0", "mask": 0, "nexthop": "192.168.121.1", "source": "192.168.121.101/32" } ], "dns-server": [ "192.168.121.1", "8.8.8.8" ], "dns-search": [ "gemteks.com" ], "inactive": { "ipv4-address": [ ], "ipv6-address": [ ], "route": [ ], "dns-server": [ ], "dns-search": [ ] }, "data": { "leasetime": 86400 } }

Approaches of data flow

There are three delivery schemes to implement IPC in Ubus.

  1. One-to-one

    • Post data or requests to specific object.
  2. One-to-many(group by object)

    • Post data to multiple subscribers that subscribed to this object.
  3. One-to-many(group by event)

    • Post data to multiple listeners of same event pattern.

Data flow sequence of UBUS

As mentioned, There are three delivery schemes to implement IPC in Ubus

  1. Invoke
    • Post data directly to one object with object ID.
  2. Subscribe/Notify
    • Post data to multiple subscribers that subscribed to same object.
  3. Event boardcast
    • Post data to multiple listeners of same event pattern.

1. Invoke

Data flow of invoke.

  1. Startup of UBUSD.
  2. Connection establishment of Process 1.
  3. Registration of Process 1 object with provided method.
  4. Connection establishment of Process 2.
  5. Object id lookup.
  6. Request with object id, method, and required data(msg).
  7. Deregistration of object.

Syntax:
-> :Client to Ubusd
->:Ubusd to Client

Created with Raphaël 2.2.0UBUSDUBUSDUBUS CLIENT 1Process 1UBUS CLIENT 1Process 1UBUS CLIENT 2Process 2UBUS CLIENT 2Process 20: create socket bind listen1.1: Connect1.2: Accept1.3: Hello2.1: Regist object, method2.2: Update Avl-treeAssign and add objpath, objid, objtype, method to avl-tree.3.1: Connect3.2: Accept3.3: Hello4.1: Lookup:{objpath}4.2: Reply data:{objpath, objid, objtype, signature}Signature includes methods and required parameters of each method.5.1: Invoke:{objid, method, msg}5.2: Invoke:{objid, method, msg}5.3: Reply data:{objid, msg}5.4: Reply data:{objid, msg}6.1: Remove:{objid}6.2:Update avl-treeRemove object with matched objpath.6.2: Reply data:{objid}

Ubus Traffic

Directions:
-> ubusd to object
<- object to ubusd

Dir. Obj.ID Ubus.ID Message Type Message -> 2d0a3716 #2d0a3716 hello: {} <- 2d0a3716 #00000000 add_object: {"objpath":"gserver.host","signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> 47dfa5f0 #00000000 invoke: {"objid":-921749017,"method":"ubus.object.add","data":{"id":-862368938,"path":"gserver.host"}} -> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862} -> 2d0a3716 #00000000 status: {"status":0} <- 47dfa5f0 #00000000 status: {"status":0,"objid":-921749017} -> 41a666fd #41a666fd hello: {} <- 41a666fd #00000000 lookup: {"objpath":"gserver.host"} -> 41a666fd #00000000 data: {"objpath":"gserver.host","objid":-862368938,"objtype":619811862,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> 41a666fd #00000000 status: {"status":0} <- 41a666fd #cc994b56 invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"}} -> 2d0a3716 #41a666fd invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"},"user":"root","group":"root"} <- 2d0a3716 #41a666fd data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}} -> 41a666fd #cc994b56 data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}} <- 2d0a3716 #41a666fd status: {"status":0,"objid":-862368938}​ -> 41a666fd #cc994b56 status: {"status":0,"objid":-862368938} -> b5d12db5 #b5d12db5 hello: {} <- b5d12db5 #00000000 lookup: {"objpath":"gserver.host"} -> b5d12db5 #00000000 data: {"objpath":"gserver.host","objid":-862368938,"objtype":619811862,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> b5d12db5 #00000000 status: {"status":0} <- b5d12db5 #cc994b56 invoke: {"objid":-862368938,"method":"gserver_stop","data":{}} -> 2d0a3716 #b5d12db5 invoke: {"objid":-862368938,"method":"gserver_stop","data":{},"user":"root","group":"root"} <- 2d0a3716 #00000000 remove_object: {"objid":-862368938} -> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862} -> 2d0a3716 #00000000 status: {"status":0} <- 2d0a3716 #b5d12db5 status: {"status":0,"objid":-862368938}
1. Connection establishment of Gserver.
-> 2d0a3716 #2d0a3716 hello: {}
2. Registration of Gserver object with provided method.
<- 2d0a3716 #00000000 add_object: {"objpath":"gserver.host","signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> 47dfa5f0 #00000000 invoke: {"objid":-921749017,"method":"ubus.object.add","data":{"id":-862368938,"path":"gserver.host"}} -> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862} -> 2d0a3716 #00000000 status: {"status":0} <- 47dfa5f0 #00000000 status: {"status":0,"objid":-921749017}
3. Connection establishment of Process 2.
-> 41a666fd #41a666fd hello: {}
4. Object id lookup.
<- 41a666fd #00000000 lookup: {"objpath":"gserver.host"} -> 41a666fd #00000000 data: {"objpath":"gserver.host","objid":-862368938,"objtype":619811862,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> 41a666fd #00000000 status: {"status":0}
5. Request with object id, method, and required data(msg).
<- 41a666fd #cc994b56 invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"}} -> 2d0a3716 #41a666fd invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"},"user":"root","group":"root"} <- 2d0a3716 #41a666fd data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}} -> 41a666fd #cc994b56 data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}} <- 2d0a3716 #41a666fd status: {"status":0,"objid":-862368938} -> 41a666fd #cc994b56 status: {"status":0,"objid":-862368938}
6. Deregistration of object.
<- 2d0a3716 #00000000 remove_object: {"objid":-862368938} -> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862} -> 2d0a3716 #00000000 status: {"status":0} <- 2d0a3716 #b5d12db5 status: {"status":0,"objid":-862368938}

2. Subscribe/notify

Data flow of Subscribe/notify.

  1. Startup of UBUSD.
  2. Connection establishment of Process 1.
  3. Registration of Process 1 object with provided method.
  4. Connection establishment of Process 3.
  5. Object id lookup.
  6. Client 3 subscribe with object id.
  7. Notification process.
  8. Client 3 unsubscribe with object id.

Sequence Diagram

Created with Raphaël 2.2.0UBUSDUBUSDUBUS CLIENT 1Process 1UBUS CLIENT 1Process 1UBUS CLIENT 3Process 3UBUS CLIENT 3Process 30: create socket bind listen2.1: Regist object, method2.2: Update Avl-tree3.1: Connect3.2: Accept3.3: Hello4.1: Lookup:{objpath}4.2: Reply data:{objpath, objid, objtype, signature}5.1: Subscribe:{objid}5.2: Update Subscription-tree5.3: Notify:{objid(subscriber), active:true}6.0 Trigger Notification6.1: Notify:{objid, msg}6.2: Lookup Subscription-tree6.3: Invoke:{objid, msg}7.1: Unsubscribe:{objid}7.2: Update Subscription-tree7.3 Notify:{objid(subscriber), active:false}

Ubus Traffic

Dir. Obj.ID Ubus.ID Message Type Message -> 74f42091 #74f42091 hello: {} <- 74f42091 #00000000 add_object: {"objpath":"gserver.host","signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> ea7bde21 #00000000 invoke: {"objid":-804320694,"method":"ubus.object.add","data":{"id":629913760,"path":"gserver.host"}} -> 74f42091 #00000000 data: {"objid":629913760,"objtype":-429408539} -> 74f42091 #00000000 status: {"status":0} <- ea7bde21 #00000000 status: {"status":0,"objid":-804320694} -> 478023e4 #478023e4 hello: {} <- 478023e4 #00000000 add_object: {} -> 478023e4 #00000000 data: {"objid":-1244318547} -> 478023e4 #00000000 status: {"status":0} <- 478023e4 #00000000 lookup: {"objpath":"gserver.host"} -> 478023e4 #00000000 data: {"objpath":"gserver.host","objid":629913760,"objtype":-429408539,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}} -> 478023e4 #00000000 status: {"status":0} <- 478023e4 #00000000 subscribe: {"objid":-1244318547} -> 74f42091 #00000000 notify: {"objid":629913760,"active":true} -> 478023e4 #00000000 status: {"status":0} ~~~~~~Notification Trigger~~~~~~ <- 74f42091 #258bb8a0 notify: {"objid":629913760,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true} -> 478023e4 #74f42091 invoke: {"objid":-1244318547,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true,"user":"root","group":"root"} <- 478023e4 #00000000 unsubscribe: {"objid":-1244318547} -> 74f42091 #00000000 notify: {"objid":629913760,"active":false}
5. Subscribe with object id.
<- 478023e4 #00000000 subscribe: {"objid":-1244318547} -> 74f42091 #00000000 notify: {"objid":629913760,"active":true} -> 478023e4 #00000000 status: {"status":0}
6. Notification process.
<- 74f42091 #258bb8a0 notify: {"objid":629913760,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true} -> 478023e4 #74f42091 invoke: {"objid":-1244318547,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true,"user":"root","group":"root"}
7. Unsubscribe with object id.
<- 478023e4 #00000000 unsubscribe: {"objid":-1244318547} -> 74f42091 #00000000 notify: {"objid":629913760,"active":false}

3. Event Boardcast

Data flow of Event Boardcast.

  1. Startup of UBUSD.
  2. Connection establishment.
  3. Receivers register to ubus event handler(objid:1) with interested event pattern.
  4. Sender sends data to ubus event handler(objid:1) with event pattern. Ubus event handler boardcasts data to receivers registered with same event pattern.

Sequence Diagram

Created with Raphaël 2.2.0UBUSDUBUSDUBUS CLIENT 1Process 1UBUS CLIENT 1Process 1UBUS CLIENT 2Process 2UBUS CLIENT 2Process 20: create socket bind listen1.1: Connect1.2 Accept1.3 Hello1.4: Connect1.5 Accept1.6 Hello2.1: Invoke:{objid, method:"register",data:{object, pattern}}2.2: Update Event Registration-tree3.1: Invoke:{objid, method:"send",data:{pattern, data}}3.2: Lookup Event Registration-tree3.3: Invoke:{objid, method:pattern, data}

Ubus Traffic

Dir. Obj.ID Ubus.ID Message Type Message -> 55484d34 #55484d34 hello: {} <- 55484d34 #00000000 add_object: {} -> 55484d34 #00000000 data: {"objid":-964689289} -> 55484d34 #00000000 status: {"status":0} <- 55484d34 #00000001 invoke: {"objid":1,"method":"register","data":{"object":-964689289,"pattern":"g_server"}} -> 55484d34 #00000001 status: {"status":0} -> b79aea68 #b79aea68 hello: {} <- b79aea68 #00000001 invoke: {"objid":1,"method":"send","data":{"id":"g_server","data":{"str":"gemtek"}}} -> 55484d34 #00000000 invoke: {"objid":-964689289,"method":"g_server","data":{"str":"gemtek"}} -> b79aea68 #00000001 status: {"status":0} <- 55484d34 #00000000 status: {"status":0,"objid":-964689289}
2. Receivers register to ubus event handler.
<- 55484d34 #00000001 invoke: {"objid":1,"method":"register","data":{"object":-964689289,"pattern":"g_server"}} -> 55484d34 #00000001 status: {"status":0}
3. Sender send data to ubus event handler(objid:1) with event pattern. Ubus event handler boardcasts data to receivers registered with *same event pattern.
<- b79aea68 #00000001 invoke: {"objid":1,"method":"send","data":{"id":"g_server","data":{"str":"gemtek"}}} -> 55484d34 #00000000 invoke: {"objid":-964689289,"method":"g_server","data":{"str":"gemtek"}}

UBUS tools

OpenWrt provides four tools to access ubus

  1. Command-line ubus tool
  2. C library libubus
  3. Ubus Lua module

Command-line ubus tool

The command "ubus" allows user to interact with the ubusd server. Services registered to ubusd server can be accessed by this command tool.

Help output of command "ubus"

root@ugwcpe:/# ubus 
Usage: ubus [<options>] <command> [arguments...]
Options:
 -s <socket>:           Set the unix domain socket to connect to
 -t <timeout>:          Set the timeout (in seconds) for a command to complete
 -S:                    Use simplified output (for scripts)
 -v:                    More verbose output
 -m <type>:             (for monitor): include a specific message type
                        (can be used more than once)
 -M <r|t>               (for monitor): only capture received or transmitted traffic

Commands:
 - list [<path>]                        List objects
 - call <path> <method> [<message>]     Call an object method
 - listen [<path>...]                   Listen for events
 - send <type> [<message>]              Send an event
 - wait_for <object> [<object>...]      Wait for multiple objects to appear on ubus
 - monitor                              Monitor ubus traffic

list

To find out services currently running on the bus, just simply use the ubus list command. A complete list of all object registed with namespace will be shown.

root@ugwcpe:/# ubus list
block
csd
devmd
dhcp
diagnosticsd
dwpald
firewalld
log
network
network.device
network.interface
network.interface.iface_eth0_1
network.interface.iface_eth0_2
network.interface.iface_eth0_3
network.interface.iface_eth0_4
network.interface.iface_eth1
network.interface.lan
network.interface.loopback
network.interface.wan3
network.wireless
polld
servd
service
system
uci
wsd

To find out methods and the argument signatures provided by specific service/object, we can type the service namespace, system, after the command list and use the option -v.

root@ugwcpe:/# ubus -v list system
'system' @d1165900
        "board":{}
        "info":{}
        "reboot":{}
        "upgrade":{}
        "done":{}
        "watchdog":{"frequency":"Integer","timeout":"Integer","magicclose":"Boolean","stop":"Boolean"}
        "signal":{"pid":"Integer","signum":"Integer"}
        "sysupgrade":{"path":"String","prefix":"String","command":"String"}
        "factoryreset":{"value":"String"}
        "hostname":{"value":"String"}

call

To call method of specific object, we can use the call command. Here is an example of call command. As there is no required data in method status, we just need to type info after object system.
The method being called takes actions, says return message, or turn on/off other services, depends on its callback function. In this case, the method info of system returns a message with system information to the callee.

root@ugwcpe:/# ubus call system info
{
        "localtime": 1610460661,
        "uptime": 82303,
        "load": [
                196608,
                196608,
                196608
        ],
        "memory": {
                "total": 1021562880,
                "free": 884396032,
                "shared": 1159168,
                "buffered": 9117696
        },
        "swap": {
                "total": 0,
                "free": 0
        }
}

send

To send message to an event with specific event pattern, we can use the send command. The following example is sending data {"str":"gemtek"} to event event_a.

root@ugwcpe:/# ubus send event_a '{"str":"gemtek"}'

listen

Command listen is for listening to events. The following example is listening to event event_a. The console prints data of related event update.

root@ugwcpe:/# ubus listen event_a
{ "event_a": {"str":"gemtek"} }

wait_for

Command wait_for returns when object waited is registered.

root@(none):/# ubus wait_for gserver.host
root@(none):/#

monitor

Command monitor is for monitoring ubus traffic.

root@ugwcpe:/# ubus monitor
-> d17cae6a #00000003         status: {"status":0}
-> 23f12bf1 #23f12bf1          hello: {}
<- 23f12bf1 #00000001         invoke: {"objid":1,"method":"send","data":{"id":"event_a","data":{"str":"gemtek"}}}
-> 716e9a5f #00000000         invoke: {"objid":-2003009711,"method":"event_a","data":{"str":"gemtek"}}
-> 23f12bf1 #00000001         status: {"status":0}
<- 716e9a5f #00000000         status: {"status":0,"objid":-2003009711}

Library libubus

Function for object registration

Function Description
struct ubus_context *ubus_connect(const char *path) Connect the specified path, create and return the ubus context represented by the path.
inline void ubus_add_uloop(struct ubus_context *ctx) Activate UBUS; this tells U-Loop to check for ubus events (listens to ubus). It is blocking function, meaning that once we call uloop_run, it is waiting for ubus to get something.
int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id) This routine gets id from path. If it is successful, it returns UBUS_STATUS_OK, otherwise UBUS_STATUS_* error-code.
void ubus_free(struct ubus_context *ctx) It is identical to ubus_shutdown() + freeing the context.
int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj) Add a UBUS object into the list of objects to be queried. We must call this routine before doing ubus_lookup_id.
int ubus_remove_object(struct ubus_context *ctx, struct ubus_object *obj) The opposite of ubus_add_object; called when we need to cleanup the pending request.

Function for request

Function Description
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) Invoke RPC indicated in passed parameter method. cb is the callback object for server object responding with data.
int ubus_send_reply(struct ubus_context *ctx, struct ubus_request *req, struct blob_attr *msg) Send reply to the incoming object call, says invoke.

Function for subscription

Function Description
int ubus_register_subscriber(struct ubus_context *ctx, struct ubus_subscriber *obj) Register a callback object for receiving notifications from publisher.
int ubus_subscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id) Subscribe to an object with a registed callback object.
int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id) Unsubscribe from the object.

Function for event

Function Description
int ubus_notify(struct ubus_context *ctx, struct ubus_object *obj, const char *type, struct blob_attr *msg, int timeout) Send notification to ubus, ubus invokes subscribers with data carried by the notification.
int ubus_register_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *pattern) Register event handler ev to the event on ubus.
int ubus_unregister_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev) Deregister event handler ev on ubus.
int ubus_send_event(struct ubus_context *ctx, const char *id, struct blob_attr *data) Send data as an event with event pattern id to ubus. Ubus call related event handlers with the data.

Sample code of server object

#include <stdio.h> #include <stdint.h> #include <libubus.h> #include <libubox/uloop.h> #include <libubox/blobmsg_json.h> /* Ubus method_call_functions */ static int gserver_post(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg); static int gserver_stop(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg); /* Enum for GSERVER policy order */ enum { GSERVER_ID, GSERVER_DATA, GSERVER_MSG, __GSERVER_MAX, }; /* Ubus method policy */ static const struct blobmsg_policy gserver_policy[] = { [GSERVER_ID] = { .name="id", .type=BLOBMSG_TYPE_INT32}, [GSERVER_DATA] = { .name="data", .type=BLOBMSG_TYPE_INT32 }, [GSERVER_MSG] = { .name="msg", .type=BLOBMSG_TYPE_STRING }, }; static const struct blobmsg_policy gserver_stop_policy[] = { }; /* Ubus object methods */ static const struct ubus_method gserver_methods[] = { /* UBUS_METHOD(method_name, method_call_function, method_policy) */ UBUS_METHOD("gserver_post", gserver_post, gserver_policy), UBUS_METHOD("gserver_stop", gserver_stop, gserver_stop_policy) }; /* Ubus object type */ static struct ubus_object_type gserver_obj_type = UBUS_OBJECT_TYPE("gserver_uobj", gserver_methods); /* Ubus object */ static struct ubus_object gserver_object= { .name = "gserver.host", //objpath .type = &gserver_obj_type, .methods = gserver_methods, .n_methods = ARRAY_SIZE(gserver_methods), }; /* Ubus method_call_functions */ static int gserver_post(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { /* do something */ return 0; } static int gserver_stop(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { /* do something */ return 0; } void server(void) { /* 1. create an epoll instatnce descriptor poll_fd */ uloop_init(); /* 2. connect to ubusd and get ctx(context) */ struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path /* 3. registger epoll events to uloop, start socket listening */ ubus_add_uloop(ctx); /* 4. register a ubus_object to ubusd */ ubus_add_object(ctx, gserver_object); /* 5. uloop routine: events monitoring and callback provoking */ uloop_run(); /* 6. terminate uloop */ uloop_done(); return; }

Sample code of client object

#include <stdio.h> #include <string.h> #include <unistd.h> #include <libubus.h> #include <libubox/uloop.h> #include <libubox/blobmsg_json.h> static struct ubus_context *ctx; static struct ubus_request_data req_data; static struct blob_buf b_buf; //message carried in invoke static uint32_t obj_id; /* Ubus object */ static struct ubus_object client_object = { }; /* callback */ static int callback (struct ubus_request *req, int type, struct blob_attr *msg) { /* do something */ return 0; } void client(void) { /* 1. create an epoll instatnce descriptor poll_fd */ uloop_init(); /* 2. connect to ubusd and get ctx(context) */ struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path /* 3. registger epoll events to uloop, start socket listening */ ubus_add_uloop(ctx); /* 4. register a ubus_object to ubusd */ ubus_add_object(ctx, &client_object); /* 5. lookup object_id of service object */ ubus_lookup_id(ctx, "gserver.host", &obj_id); /* 6. send request by ubus_invoke to service object */ ubus_invoke(ctx, obj_id, "gserver_post", b_buf, callback, 0, 3000); /* 7. uloop routine: events monitoring and callback provoking */ uloop_run(); /* 8. terminate uloop */ uloop_done(); return; }

Sample code for subscriber

#include <stdio.h> #include <string.h> #include <unistd.h> #include <libubus.h> #include <libubox/uloop.h> #include <libubox/blobmsg_json.h> static struct ubus_context *ctx; static uint32_t obj_id; static int notif_handler(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, struct blob_attr *msg) { /* do something */ return 0; } void subscriber_object(void) { /* 1. create an epoll instatnce descriptor poll_fd */ uloop_init(); /* 2. connect to ubusd and get ctx(context) */ struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path /* 3. registger epoll events to uloop, start socket listening */ ubus_add_uloop(ctx); /* 4. register a ubus_object to ubusd */ ubus_add_object(ctx, &subscriber_object); /* 5. lookup object_id of service object */ ubus_lookup_id(ctx, "gserver.host", &obj_id); /* 6. subscribe service object */ ubus_subscribe(ctx, &notif_handler, obj_id); /* 7. uloop routine: events monitoring and callback provoking */ uloop_run(); /* 8. terminate uloop */ uloop_done(); return; }

Sample code for event listener

#include <stdio.h> #include <string.h> #include <unistd.h> #include <libubus.h> #include <libubox/uloop.h> #include <libubox/blobmsg_json.h> static struct ubus_context *ctx; static struct ubus_request_data req_data; static struct blob_buf b_buf; static uint32_t obj_id; static void receive_event(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *method, struct blob_attr *msg) { printf("Event received\n"); /* do something */ return; } int event_example () { /* 1. create an epoll instatnce descriptor poll_fd */ uloop_init(); /* 2. connect to ubusd and get ctx(context) */ struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path /* 3. registger epoll events to uloop, start socket listening */ ubus_add_uloop(ctx); /* 4. register event on ubus */ const char *event = "gevent"; struct ubus_event_handler ev = { .cb = receive_event, }; ubus_register_event_handler(ctx, &ev, event); /* 5. uloop routine: events monitoring */ uloop_run(); /* 6. terminate uloop */ uloop_done(); return; }

References

https://openwrt.org/docs/techref/ubus
https://openwrt.org/docs/techref/libubox
https://www.programmersought.com/article/32835484946/
https://www.programmersought.com/article/26351479004/
https://www.programmersought.com/article/48733667380/