summaryrefslogtreecommitdiff
path: root/libubus.h
blob: 6925514adb0fcea7929e52f67adabc04cbeacfaa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/*
 * 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

#ifdef __cplusplus
extern "C" {
#endif

#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_notify_data_handler_t)(struct ubus_notify_request *req,
					   int type, struct blob_attr *msg);
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, _tags)	\
	.name = _name,					\
	.handler = _handler,				\
	.tags = _tags

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

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

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

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

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

#define UBUS_METHOD_TAG_NOARG(_name, _handler, _tags)	\
	{ __UBUS_METHOD_NOARG(_name, _handler, _tags) }

#define UBUS_TAG_STATUS		BIT(0)
#define UBUS_TAG_ADMIN		BIT(1)
#define UBUS_TAG_PRIVATE	BIT(2)

struct ubus_method {
	const char *name;
	ubus_handler_t handler;

	unsigned long mask;
	unsigned long tags;
	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;
	bool cancel_poll;
	int stack_depth;

	void (*connection_lost)(struct ubus_context *ctx);
	void (*monitor_cb)(struct ubus_context *ctx, uint32_t seq, struct blob_attr *data);

	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_acl_key {
	const char *user;
	const char *group;
	const char *object;
};

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

	struct ubus_acl_key acl;

	/* internal use */
	bool deferred;
	int fd;
	int req_fd; /* fd received from the initial request */
};

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;

	int fd;

	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;
	ubus_notify_data_handler_t data_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);
int ubus_connect_ctx(struct ubus_context *ctx, const char *path);
void ubus_auto_connect(struct ubus_auto_conn *conn);
int ubus_reconnect(struct ubus_context *ctx, const char *path);

/* call this only for struct ubus_context pointers returned by ubus_connect() */
void ubus_free(struct ubus_context *ctx);

/* call this only for struct ubus_context pointers initialised by ubus_connect_ctx() */
void ubus_shutdown(struct ubus_context *ctx);

static inline void ubus_auto_shutdown(struct ubus_auto_conn *conn)
{
	uloop_timeout_cancel(&conn->timer);
	ubus_shutdown(&conn->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);

int __ubus_monitor(struct ubus_context *ctx, const char *type);

static inline int ubus_monitor_start(struct ubus_context *ctx)
{
	return __ubus_monitor(ctx, "add");
}

static inline int ubus_monitor_stop(struct ubus_context *ctx)
{
	return __ubus_monitor(ctx, "remove");
}


/* ----------- acl ----------- */

struct acl_object {
	struct ubus_acl_key key;
	struct avl_node avl;
	struct blob_attr *acl;
};

extern struct avl_tree acl_objects;
int ubus_register_acl(struct ubus_context *ctx);

#define acl_for_each(o, m) \
	if ((m)->object && (m)->user && (m)->group) \
		avl_for_element_range(avl_find_ge_element(&acl_objects, m, o, avl), avl_find_le_element(&acl_objects, m, o, avl), o, avl)

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

/* invoke a method on a specific object */
int ubus_invoke_fd(struct ubus_context *ctx, uint32_t obj, const char *method,
		struct blob_attr *msg, ubus_data_handler_t cb, void *priv,
		int timeout, int fd);
static inline 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)
{
	return ubus_invoke_fd(ctx, obj, method, msg, cb, priv, timeout, -1);
}

/* asynchronous version of ubus_invoke() */
int ubus_invoke_async_fd(struct ubus_context *ctx, uint32_t obj, const char *method,
		      struct blob_attr *msg, struct ubus_request *req, int fd);
static inline int
ubus_invoke_async(struct ubus_context *ctx, uint32_t obj, const char *method,
		  struct blob_attr *msg, struct ubus_request *req)
{
	return ubus_invoke_async_fd(ctx, obj, method, msg, req, -1);
}

/* 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)
{
    (void) ctx;
    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)
{
    (void) ctx;
    req->fd = fd;
}

static inline int ubus_request_get_caller_fd(struct ubus_request_data *req)
{
    int fd = req->req_fd;
    req->req_fd = -1;
    
    return 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);
}

#ifdef __cplusplus
}
#endif

#endif