Allow sending a fd along a ubus_request
authoramine ahd <amine.ahd@gmail.com>
Mon, 19 Dec 2016 09:30:36 +0000 (10:30 +0100)
committerFelix Fietkau <nbd@nbd.name>
Sat, 24 Dec 2016 13:31:04 +0000 (14:31 +0100)
Signed-off-by: amine.ahd <amine.ahd@gmail.com>
libubus-internal.h
libubus-obj.c
libubus-req.c
libubus.c
libubus.h
ubusd_proto.c

index f62edc388bd6e65d58100bce97778819bb5ce054..c4067d3438177ffdaa22bdc23575def9f3177bcf 100644 (file)
@@ -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);
 
index 990d04bd9844b8d590c555193742575e58e1458f..a9972c5862eae0d62469e3010c346ed378877d12 100644 (file)
  * 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)
index 416adaba2f9fca50225d9915b2512026a7b481f1..5180a6f828625a6ca476ff7cb837c414d7d27f23 100644 (file)
@@ -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)
 {
index 8163ff7004fb6e23487a7661f9c55b8cc9a55783..b25d8b084f9b6271bfd1625c24549c25edfb2a78 100644 (file)
--- 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)
index 07239d6664d4ade26de378df46d4e44d9876b413..350e694db83993cabd8fb9cac33da395823585fe 100644 (file)
--- 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);
 
index d2feed9aa3ae027b648586ade4d5803d23b51960..72da7a73f22f4bf2176fa93a605b8a5bfa99f87d 100644 (file)
@@ -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)