Allow sending a fd along a ubus_request
Signed-off-by: amine.ahd <amine.ahd@gmail.com>
This commit is contained in:
parent
5ca6bae3a2
commit
df088f03c0
6 changed files with 91 additions and 14 deletions
|
@ -24,7 +24,9 @@ int ubus_send_msg(struct ubus_context *ctx, uint32_t seq,
|
|||
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);
|
||||
|
||||
|
|
|
@ -11,12 +11,13 @@
|
|||
* 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;
|
||||
|
||||
|
@ -29,11 +30,13 @@ ubus_process_unsubscribe(struct ubus_context *ctx, struct ubus_msghdr *hdr,
|
|||
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;
|
||||
|
@ -41,14 +44,18 @@ ubus_process_notify(struct ubus_context *ctx, struct ubus_msghdr *hdr,
|
|||
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;
|
||||
|
@ -65,7 +72,7 @@ ubus_process_invoke(struct ubus_context *ctx, struct ubus_msghdr *hdr,
|
|||
|
||||
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;
|
||||
|
@ -88,6 +95,7 @@ found:
|
|||
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;
|
||||
|
||||
|
@ -95,16 +103,16 @@ send:
|
|||
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;
|
||||
|
@ -131,7 +139,7 @@ void __hidden ubus_process_obj_msg(struct ubus_context *ctx, struct ubus_msghdr_
|
|||
buf->data = NULL;
|
||||
}
|
||||
|
||||
cb(ctx, hdr, obj, attrbuf);
|
||||
cb(ctx, hdr, obj, attrbuf, fd);
|
||||
|
||||
if (prev_data) {
|
||||
if (buf->data)
|
||||
|
|
|
@ -49,10 +49,9 @@ static void __ubus_process_req_data(struct ubus_request *req)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -62,9 +61,21 @@ int __hidden ubus_start_request(struct ubus_context *ctx, struct ubus_request *r
|
|||
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))
|
||||
|
@ -224,6 +235,23 @@ int ubus_invoke_async(struct ubus_context *ctx, uint32_t obj, const char *method
|
|||
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)
|
||||
|
@ -240,6 +268,22 @@ int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method,
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -103,7 +103,7 @@ ubus_process_msg(struct ubus_context *ctx, struct ubus_msghdr_buf *buf, int fd)
|
|||
break;
|
||||
}
|
||||
|
||||
ubus_process_obj_msg(ctx, buf);
|
||||
ubus_process_obj_msg(ctx, buf, fd);
|
||||
break;
|
||||
case UBUS_MSG_MONITOR:
|
||||
if (ctx->monitor_cb)
|
||||
|
|
19
libubus.h
19
libubus.h
|
@ -188,6 +188,7 @@ struct ubus_request_data {
|
|||
/* internal use */
|
||||
bool deferred;
|
||||
int fd;
|
||||
int req_fd; /* fd received from the initial request */
|
||||
};
|
||||
|
||||
struct ubus_request {
|
||||
|
@ -208,6 +209,8 @@ struct ubus_request {
|
|||
ubus_fd_handler_t fd_cb;
|
||||
ubus_complete_handler_t complete_cb;
|
||||
|
||||
int fd;
|
||||
|
||||
struct ubus_context *ctx;
|
||||
void *priv;
|
||||
};
|
||||
|
@ -336,6 +339,14 @@ int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method,
|
|||
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);
|
||||
|
@ -356,6 +367,14 @@ static inline void ubus_request_set_fd(struct ubus_context *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);
|
||||
|
||||
|
|
|
@ -80,11 +80,15 @@ void
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -447,7 +451,7 @@ void ubusd_proto_receive_message(struct ubus_client *cl, struct ubus_msg_buf *ub
|
|||
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)
|
||||
|
|
Loading…
Reference in a new issue