CMakeLists.txt: bump minimum cmake version
[project/ubus.git] / ubusd.c
diff --git a/ubusd.c b/ubusd.c
index 0d43977c0bde920077b806f850c6607fecd5b958..1d76b72e42867de81f2527bc288bc017535b5f0b 100644 (file)
--- a/ubusd.c
+++ b/ubusd.c
@@ -82,27 +82,28 @@ void ubus_msg_free(struct ubus_msg_buf *ub)
 
 ssize_t ubus_msg_writev(int fd, struct ubus_msg_buf *ub, size_t offset)
 {
+       uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
        static struct iovec iov[2];
-       static struct {
-               int fd;
-               struct cmsghdr h;
-       } fd_buf = {
-               .h = {
-                       .cmsg_len = sizeof(fd_buf),
-                       .cmsg_level = SOL_SOCKET,
-                       .cmsg_type = SCM_RIGHTS,
-               },
-       };
-       struct msghdr msghdr = {
-               .msg_iov = iov,
-               .msg_iovlen = ARRAY_SIZE(iov),
-               .msg_control = &fd_buf,
-               .msg_controllen = sizeof(fd_buf),
-       };
+       struct msghdr msghdr = { 0 };
        struct ubus_msghdr hdr;
+       struct cmsghdr *cmsg;
        ssize_t ret;
+       int *pfd;
 
-       fd_buf.fd = ub->fd;
+       msghdr.msg_iov = iov;
+       msghdr.msg_iovlen = ARRAY_SIZE(iov);
+       msghdr.msg_control = fd_buf;
+       msghdr.msg_controllen = sizeof(fd_buf);
+
+       cmsg = CMSG_FIRSTHDR(&msghdr);
+       cmsg->cmsg_type = SCM_RIGHTS;
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+       pfd = (int *) CMSG_DATA(cmsg);
+       msghdr.msg_controllen = cmsg->cmsg_len;
+
+       *pfd = ub->fd;
        if (ub->fd < 0 || offset) {
                msghdr.msg_control = NULL;
                msghdr.msg_controllen = 0;
@@ -132,13 +133,29 @@ ssize_t ubus_msg_writev(int fd, struct ubus_msg_buf *ub, size_t offset)
        return ret;
 }
 
+void ubus_msg_list_free(struct ubus_msg_buf_list *ubl)
+{
+       list_del_init(&ubl->list);
+       ubus_msg_free(ubl->msg);
+       free(ubl);
+}
+
 static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub)
 {
-       if (cl->tx_queue[cl->txq_tail])
+       struct ubus_msg_buf_list *ubl;
+
+       if (cl->txq_len + ub->len > UBUS_CLIENT_MAX_TXQ_LEN)
                return;
 
-       cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub);
-       cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue);
+       ubl = calloc(1, sizeof(struct ubus_msg_buf_list));
+       if (!ubl)
+               return;
+
+       INIT_LIST_HEAD(&ubl->list);
+       ubl->msg = ubus_msg_ref(ub);
+
+       list_add_tail(&ubl->list, &cl->tx_queue);
+       cl->txq_len += ub->len;
 }
 
 /* takes the msgbuf reference */
@@ -149,7 +166,7 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub)
        if (ub->hdr.type != UBUS_MSG_MONITOR)
                ubusd_monitor_message(cl, ub, true);
 
-       if (!cl->tx_queue[cl->txq_cur]) {
+       if (list_empty(&cl->tx_queue)) {
                written = ubus_msg_writev(cl->sock.fd, ub, 0);
 
                if (written < 0)
@@ -159,6 +176,7 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub)
                        return;
 
                cl->txq_ofs = written;
+               cl->txq_len = -written;
 
                /* get an event once we can write to the socket again */
                uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER);