void ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd);
int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
struct blob_attr *msg, int cmd, uint32_t peer);
-void ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf);
+int __hidden __ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
+ struct blob_attr *msg, int cmd, uint32_t peer);
+void ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd);
void ubus_process_req_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd);
void __hidden ubus_poll_data(struct ubus_context *ctx, int timeout);
* GNU General Public License for more details.
*/
+#include <unistd.h>
#include "libubus.h"
#include "libubus-internal.h"
static void
ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr,
- struct ubus_object *obj, struct blob_attr **attrbuf)
+ struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
{
struct ubus_subscriber *s;
s = container_of(obj, struct ubus_subscriber, obj);
if (s->remove_cb)
s->remove_cb(ctx, s, blob_get_u32(attrbuf[UBUS_ATTR_TARGET]));
+
+ close(fd);
}
static void
ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr,
- struct ubus_object *obj, struct blob_attr **attrbuf)
+ struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
{
if (!obj || !attrbuf[UBUS_ATTR_ACTIVE])
return;
obj->has_subscribers = blob_get_u8(attrbuf[UBUS_ATTR_ACTIVE]);
if (obj->subscribe_cb)
obj->subscribe_cb(ctx, obj);
+
+ close(fd);
}
static void
ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr,
- struct ubus_object *obj, struct blob_attr **attrbuf)
+ struct ubus_object *obj, struct blob_attr **attrbuf, int fd)
{
struct ubus_request_data req = {
.fd = -1,
+ .req_fd = fd,
};
+
int method;
int ret;
bool no_reply = false;
if (attrbuf[UBUS_ATTR_NO_REPLY])
no_reply = blob_get_int8(attrbuf[UBUS_ATTR_NO_REPLY]);
-
+
req.peer = hdr->peer;
req.seq = hdr->seq;
req.object = obj->id;
ret = obj->methods[method].handler(ctx, obj, &req,
blob_data(attrbuf[UBUS_ATTR_METHOD]),
attrbuf[UBUS_ATTR_DATA]);
+ close(req.req_fd);
if (req.deferred || no_reply)
return;
ubus_complete_deferred_request(ctx, &req, ret);
}
-void __hidden ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf)
+
+void __hidden ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd)
{
void (*cb)(struct ubus_context *, struct ubus_msghdr *,
- struct ubus_object *, struct blob_attr **);
+ struct ubus_object *, struct blob_attr **, int fd);
struct ubus_msghdr *hdr = &buf->hdr;
struct blob_attr **attrbuf;
struct ubus_object *obj;
uint32_t objid;
void *prev_data = NULL;
-
attrbuf = ubus_parse_msg(buf->data);
if (!attrbuf[UBUS_ATTR_OBJID])
return;
buf->data = NULL;
}
- cb(ctx, hdr, obj, attrbuf);
+ cb(ctx, hdr, obj, attrbuf, fd);
if (prev_data) {
if (buf->data)
}
}
-int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
+int __hidden __ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
struct blob_attr *msg, int cmd, uint32_t peer)
{
- memset(req, 0, sizeof(*req));
if (msg && blob_pad_len(msg) > UBUS_MAX_MSGLEN)
return -1;
req->ctx = ctx;
req->peer = peer;
req->seq = ++ctx->request_seq;
- return ubus_send_msg(ctx, req->seq, msg, cmd, peer, -1);
+
+ return ubus_send_msg(ctx, req->seq, msg, cmd, peer, req->fd);
}
+int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *req,
+ struct blob_attr *msg, int cmd, uint32_t peer)
+{
+ memset(req, 0, sizeof(*req));
+
+ req->fd = -1;
+
+ return __ubus_start_request(ctx, req, msg, cmd, peer);
+}
+
+
void ubus_abort_request(struct ubus_context *ctx, struct ubus_request *req)
{
if (list_empty(&req->list))
return 0;
}
+
+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)
+{
+ blob_buf_init(&b, 0);
+ blob_put_int32(&b, UBUS_ATTR_OBJID, obj);
+ blob_put_string(&b, UBUS_ATTR_METHOD, method);
+ if (msg)
+ blob_put(&b, UBUS_ATTR_DATA, blob_data(msg), blob_len(msg));
+
+ memset(req, 0, sizeof(*req));
+ req->fd = fd;
+ if (__ubus_start_request(ctx, req, b.head, UBUS_MSG_INVOKE, obj) < 0)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+ return 0;
+}
+
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_complete_request(ctx, &req, timeout);
}
+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)
+{
+ struct ubus_request req;
+ int rc;
+
+ rc = ubus_invoke_async_fd(ctx, obj, method, msg, &req, fd);
+ if (rc)
+ return rc;
+
+ req.data_cb = cb;
+ req.priv = priv;
+ return ubus_complete_request(ctx, &req, timeout);
+}
+
static void
ubus_notify_complete_cb(struct ubus_request *req, int ret)
{
break;
}
- ubus_process_obj_msg(ctx, buf);
+ ubus_process_obj_msg(ctx, buf, fd);
break;
case UBUS_MSG_MONITOR:
if (ctx->monitor_cb)
/* internal use */
bool deferred;
int fd;
+ int req_fd; /* fd received from the initial request */
};
struct ubus_request {
ubus_fd_handler_t fd_cb;
ubus_complete_handler_t complete_cb;
+ int fd;
+
struct ubus_context *ctx;
void *priv;
};
int ubus_invoke_async(struct ubus_context *ctx, uint32_t obj, const char *method,
struct blob_attr *msg, struct ubus_request *req);
+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);
+
+/* 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);
+
/* 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);
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);
ubus_proto_send_msg_from_blob(struct ubus_client *cl, struct ubus_msg_buf *ub,
uint8_t type)
{
+ /* keep the fd to be passed if it is UBUS_MSG_INVOKE */
+ int fd = ub->fd;
ub = ubus_reply_from_blob(ub, true);
if (!ub)
return;
ub->hdr.type = type;
+ ub->fd = fd;
+
ubus_msg_send(cl, ub, true);
}
if (ub->hdr.type < __UBUS_MSG_LAST)
cb = handlers[ub->hdr.type];
- if (ub->hdr.type != UBUS_MSG_STATUS)
+ if (ub->hdr.type != UBUS_MSG_STATUS && ub->hdr.type != UBUS_MSG_INVOKE)
ubus_msg_close_fd(ub);
if (cb)