libubus: restore uloop_cancelled on timeout
[project/ubus.git] / libubus-io.c
index c63a920..fa53040 100644 (file)
@@ -28,6 +28,8 @@
 
 #define STATIC_IOV(_var) { .iov_base = (char *) &(_var), .iov_len = sizeof(_var) }
 
+#define UBUS_MSGBUF_REDUCTION_INTERVAL 16
+
 static const struct blob_attr_info ubus_policy[UBUS_ATTR_MAX] = {
        [UBUS_ATTR_STATUS] = { .type = BLOB_ATTR_INT32 },
        [UBUS_ATTR_OBJID] = { .type = BLOB_ATTR_INT32 },
@@ -109,7 +111,10 @@ static int writev_retry(int fd, struct iovec *iov, int iov_len, int sock_fd)
                        if (!iov_len)
                                return len;
                }
+               iov->iov_base += cur_len;
                iov->iov_len -= cur_len;
+               msghdr.msg_iov = iov;
+               msghdr.msg_iovlen = iov_len;
        } while (1);
 
        /* Should never reach here */
@@ -226,6 +231,36 @@ static bool ubus_validate_hdr(struct ubus_msghdr *hdr)
        return true;
 }
 
+static bool alloc_msg_buf(struct ubus_context *ctx, int len)
+{
+       void *ptr;
+       int buf_len = ctx->msgbuf_data_len;
+       int rem;
+
+       if (!ctx->msgbuf.data)
+               buf_len = 0;
+
+       rem = (len % UBUS_MSG_CHUNK_SIZE);
+       if (rem > 0)
+               len += UBUS_MSG_CHUNK_SIZE - rem;
+
+       if (len < buf_len &&
+           ++ctx->msgbuf_reduction_counter > UBUS_MSGBUF_REDUCTION_INTERVAL) {
+               ctx->msgbuf_reduction_counter = 0;
+               buf_len = 0;
+       }
+
+       if (len <= buf_len)
+               return true;
+
+       ptr = realloc(ctx->msgbuf.data, len);
+       if (!ptr)
+               return false;
+
+       ctx->msgbuf.data = ptr;
+       return true;
+}
+
 static bool get_next_msg(struct ubus_context *ctx, int *recv_fd)
 {
        struct {
@@ -233,6 +268,7 @@ static bool get_next_msg(struct ubus_context *ctx, int *recv_fd)
                struct blob_attr data;
        } hdrbuf;
        struct iovec iov = STATIC_IOV(hdrbuf);
+       int len;
        int r;
 
        /* receive header + start attribute */
@@ -247,6 +283,10 @@ static bool get_next_msg(struct ubus_context *ctx, int *recv_fd)
        if (!ubus_validate_hdr(&hdrbuf.hdr))
                return false;
 
+       len = blob_raw_len(&hdrbuf.data);
+       if (!alloc_msg_buf(ctx, len))
+               return false;
+
        memcpy(&ctx->msgbuf.hdr, &hdrbuf.hdr, sizeof(hdrbuf.hdr));
        memcpy(ctx->msgbuf.data, &hdrbuf.data, sizeof(hdrbuf.data));
 
@@ -261,11 +301,10 @@ static bool get_next_msg(struct ubus_context *ctx, int *recv_fd)
 void __hidden ubus_handle_data(struct uloop_fd *u, unsigned int events)
 {
        struct ubus_context *ctx = container_of(u, struct ubus_context, sock);
-       struct ubus_msghdr *hdr = &ctx->msgbuf.hdr;
        int recv_fd = -1;
 
        while (get_next_msg(ctx, &recv_fd)) {
-               ubus_process_msg(ctx, hdr, recv_fd);
+               ubus_process_msg(ctx, &ctx->msgbuf, recv_fd);
                if (uloop_cancelled)
                        break;
        }
@@ -353,7 +392,7 @@ int ubus_reconnect(struct ubus_context *ctx, const char *path)
                goto out_free;
 
        ret = UBUS_STATUS_OK;
-       fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK);
+       fcntl(ctx->sock.fd, F_SETFL, fcntl(ctx->sock.fd, F_GETFL) | O_NONBLOCK | O_CLOEXEC);
 
        ubus_refresh_state(ctx);