diff --git a/libubus-internal.h b/libubus-internal.h index f62edc3..c4067d3 100644 --- a/libubus-internal.h +++ b/libubus-internal.h @@ -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); diff --git a/libubus-obj.c b/libubus-obj.c index 990d04b..a9972c5 100644 --- a/libubus-obj.c +++ b/libubus-obj.c @@ -11,12 +11,13 @@ * GNU General Public License for more details. */ +#include #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) diff --git a/libubus-req.c b/libubus-req.c index 416adab..5180a6f 100644 --- a/libubus-req.c +++ b/libubus-req.c @@ -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) { diff --git a/libubus.c b/libubus.c index 8163ff7..b25d8b0 100644 --- a/libubus.c +++ b/libubus.c @@ -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) diff --git a/libubus.h b/libubus.h index 07239d6..350e694 100644 --- a/libubus.h +++ b/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); diff --git a/ubusd_proto.c b/ubusd_proto.c index d2feed9..72da7a7 100644 --- a/ubusd_proto.c +++ b/ubusd_proto.c @@ -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)