struct blob_attr *buf;
int ret = UBUS_STATUS_UNKNOWN_ERROR;
+ if (ubus_context_is_channel(ctx))
+ return -1;
+
if (!path)
path = UBUS_UNIX_SOCKET;
goto out_free;
ctx->local_id = hdr.hdr.peer;
- if (!ctx->local_id)
+ if (ctx->local_id <= UBUS_CLIENT_ID_CHANNEL)
goto out_free;
ret = UBUS_STATUS_OK;
.fd = -1,
.req_fd = fd,
};
-
+ ubus_handler_t handler;
int method;
int ret;
bool no_reply = false;
- if (!obj) {
+ if ((!obj && !ubus_context_is_channel(ctx)) ||
+ (!ctx->request_handler && ubus_context_is_channel(ctx))) {
ret = UBUS_STATUS_NOT_FOUND;
goto send;
}
req.peer = hdr->peer;
req.seq = hdr->seq;
+
+ if (ubus_context_is_channel(ctx)) {
+ handler = ctx->request_handler;
+ goto found;
+ }
+
req.object = obj->id;
if (attrbuf[UBUS_ATTR_USER] && attrbuf[UBUS_ATTR_GROUP]) {
req.acl.user = blobmsg_get_string(attrbuf[UBUS_ATTR_USER]);
for (method = 0; method < obj->n_methods; method++)
if (!obj->methods[method].name ||
!strcmp(obj->methods[method].name,
- blob_data(attrbuf[UBUS_ATTR_METHOD])))
+ blob_data(attrbuf[UBUS_ATTR_METHOD]))) {
+ handler = obj->methods[method].handler;
goto found;
+ }
/* not found */
ret = UBUS_STATUS_METHOD_NOT_FOUND;
goto send;
}
- ret = obj->methods[method].handler(ctx, obj, &req,
- blob_data(attrbuf[UBUS_ATTR_METHOD]),
- attrbuf[UBUS_ATTR_DATA]);
+ ret = handler(ctx, obj, &req, blob_data(attrbuf[UBUS_ATTR_METHOD]),
+ attrbuf[UBUS_ATTR_DATA]);
if (req.req_fd >= 0)
close(req.req_fd);
if (req.deferred || no_reply)
struct ubus_request req;
int ret;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
blob_buf_init(&b, 0);
if (obj->name && obj->type) {
struct ubus_request req;
int ret;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
blob_buf_init(&b, 0);
blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id);
const char *type, struct blob_attr *msg,
struct ubus_notify_request *req, bool reply)
{
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
memset(req, 0, sizeof(*req));
blob_buf_init(&b, 0);
int __ubus_monitor(struct ubus_context *ctx, const char *type)
{
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
blob_buf_init(&b, 0);
return ubus_invoke(ctx, UBUS_SYSTEM_OBJECT_MONITOR, type, b.head, NULL, NULL, 1000);
}
struct ubus_object *obj = &s->obj;
int ret;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
INIT_LIST_HEAD(&s->list);
obj->methods = &watch_method;
obj->n_methods = 1;
{
struct ubus_request req;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
blob_buf_init(&b, 0);
blob_put_int32(&b, UBUS_ATTR_OBJID, obj->id);
blob_put_int32(&b, UBUS_ATTR_TARGET, id);
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
+#include <fcntl.h>
#include <libubox/blob.h>
#include <libubox/blobmsg.h>
ubus_process_req_msg(ctx, buf, fd);
break;
- case UBUS_MSG_INVOKE:
case UBUS_MSG_UNSUBSCRIBE:
case UBUS_MSG_NOTIFY:
+ if (ubus_context_is_channel(ctx))
+ break;
+ /* fallthrough */
+ case UBUS_MSG_INVOKE:
if (ctx->stack_depth) {
ubus_queue_msg(ctx, buf);
break;
ctx->stack_depth--;
break;
case UBUS_MSG_MONITOR:
+ if (ubus_context_is_channel(ctx))
+ break;
+
if (ctx->monitor_cb)
ctx->monitor_cb(ctx, buf->hdr.seq, buf->data);
break;
{
struct ubus_lookup_request lookup;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
blob_buf_init(&b, 0);
if (path)
blob_put_string(&b, UBUS_ATTR_OBJPATH, path);
{
struct ubus_request req;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
blob_buf_init(&b, 0);
if (path)
blob_put_string(&b, UBUS_ATTR_OBJPATH, path);
struct blob_buf b2 = {};
int ret;
+ if (ubus_context_is_channel(ctx))
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
if (!obj->id) {
obj->methods = &event_method;
obj->n_methods = 1;
uloop_end();
}
-int ubus_connect_ctx(struct ubus_context *ctx, const char *path)
+static int
+__ubus_ctx_init(struct ubus_context *ctx)
{
uloop_init();
memset(ctx, 0, sizeof(*ctx));
INIT_LIST_HEAD(&ctx->requests);
INIT_LIST_HEAD(&ctx->pending);
- INIT_LIST_HEAD(&ctx->auto_subscribers);
avl_init(&ctx->objects, ubus_cmp_id, false, NULL);
+ return 0;
+}
+
+int ubus_connect_ctx(struct ubus_context *ctx, const char *path)
+{
+ if (__ubus_ctx_init(ctx))
+ return -1;
+
+ INIT_LIST_HEAD(&ctx->auto_subscribers);
if (ubus_reconnect(ctx, path)) {
free(ctx->msgbuf.data);
ctx->msgbuf.data = NULL;
return 0;
}
+int ubus_channel_connect(struct ubus_context *ctx, int fd,
+ ubus_handler_t handler)
+{
+ if (__ubus_ctx_init(ctx))
+ return -1;
+
+ if (ctx->sock.fd >= 0) {
+ if (ctx->sock.registered)
+ uloop_fd_delete(&ctx->sock);
+
+ close(ctx->sock.fd);
+ }
+
+ ctx->sock.eof = false;
+ ctx->sock.error = false;
+ ctx->sock.fd = fd;
+ ctx->local_id = UBUS_CLIENT_ID_CHANNEL;
+ ctx->request_handler = handler;
+
+ fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK | O_CLOEXEC);
+
+ return 0;
+}
+
+int ubus_channel_create(struct ubus_context *ctx, int *remote_fd,
+ ubus_handler_t handler)
+{
+ int sfd[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd))
+ return -1;
+
+ if (ubus_channel_connect(ctx, sfd[0], handler) < 0) {
+ close(sfd[0]);
+ close(sfd[1]);
+ return -1;
+ }
+
+ *remote_fd = sfd[1];
+
+ return 0;
+}
+
static void ubus_auto_reconnect_cb(struct uloop_timeout *timeout)
{
struct ubus_auto_conn *conn = container_of(timeout, struct ubus_auto_conn, timer);
uint32_t msgbuf_data_len;
int msgbuf_reduction_counter;
- struct list_head auto_subscribers;
- struct ubus_event_handler auto_subscribe_event_handler;
+ union {
+ struct {
+ struct list_head auto_subscribers;
+ struct ubus_event_handler auto_subscribe_event_handler;
+ };
+ struct {
+ ubus_handler_t request_handler;
+ };
+ };
};
struct ubus_object_data {
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);
+int ubus_channel_connect(struct ubus_context *ctx, int fd,
+ ubus_handler_t handler);
+int ubus_channel_create(struct ubus_context *ctx, int *remote_fd,
+ ubus_handler_t handler);
+
+static inline bool
+ubus_context_is_channel(struct ubus_context *ctx)
+{
+ return ctx->local_id == UBUS_CLIENT_ID_CHANNEL;
+}
/* call this only for struct ubus_context pointers returned by ubus_connect() */
void ubus_free(struct ubus_context *ctx);
#define UBUS_MSG_CHUNK_SIZE 65536
+#define UBUS_CLIENT_ID_CHANNEL 1
+
#define UBUS_SYSTEM_OBJECT_EVENT 1
#define UBUS_SYSTEM_OBJECT_ACL 2
#define UBUS_SYSTEM_OBJECT_MONITOR 3