2 * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <sys/socket.h>
16 #include <sys/param.h>
21 #define USES_EXTERNAL_BUFFER ~0U
23 static struct ubus_msg_buf
*ubus_msg_ref(struct ubus_msg_buf
*ub
)
25 struct ubus_msg_buf
*new_ub
;
26 if (ub
->refcount
== USES_EXTERNAL_BUFFER
) {
27 new_ub
= ubus_msg_new(ub
->data
, ub
->len
, false);
30 memcpy(&new_ub
->hdr
, &ub
->hdr
, sizeof(struct ubus_msghdr
));
39 struct ubus_msg_buf
*ubus_msg_new(void *data
, int len
, bool shared
)
41 struct ubus_msg_buf
*ub
;
42 int buflen
= sizeof(*ub
);
47 ub
= calloc(1, buflen
);
54 ub
->refcount
= USES_EXTERNAL_BUFFER
;
58 ub
->data
= (void *) (ub
+ 1);
60 memcpy(ub
+ 1, data
, len
);
67 void ubus_msg_free(struct ubus_msg_buf
*ub
)
69 switch (ub
->refcount
) {
71 case USES_EXTERNAL_BUFFER
:
83 ssize_t
ubus_msg_writev(int fd
, struct ubus_msg_buf
*ub
, size_t offset
)
85 uint8_t fd_buf
[CMSG_SPACE(sizeof(int))] = { 0 };
86 static struct iovec iov
[2];
87 struct msghdr msghdr
= { 0 };
88 struct ubus_msghdr hdr
;
94 msghdr
.msg_iovlen
= ARRAY_SIZE(iov
);
95 msghdr
.msg_control
= fd_buf
;
96 msghdr
.msg_controllen
= sizeof(fd_buf
);
98 cmsg
= CMSG_FIRSTHDR(&msghdr
);
99 cmsg
->cmsg_type
= SCM_RIGHTS
;
100 cmsg
->cmsg_level
= SOL_SOCKET
;
101 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
103 pfd
= (int *) CMSG_DATA(cmsg
);
104 msghdr
.msg_controllen
= cmsg
->cmsg_len
;
107 if (ub
->fd
< 0 || offset
) {
108 msghdr
.msg_control
= NULL
;
109 msghdr
.msg_controllen
= 0;
112 if (offset
< sizeof(ub
->hdr
)) {
113 hdr
.version
= ub
->hdr
.version
;
114 hdr
.type
= ub
->hdr
.type
;
115 hdr
.seq
= cpu_to_be16(ub
->hdr
.seq
);
116 hdr
.peer
= cpu_to_be32(ub
->hdr
.peer
);
118 iov
[0].iov_base
= ((char *) &hdr
) + offset
;
119 iov
[0].iov_len
= sizeof(hdr
) - offset
;
120 iov
[1].iov_base
= (char *) ub
->data
;
121 iov
[1].iov_len
= ub
->len
;
123 offset
-= sizeof(ub
->hdr
);
124 iov
[0].iov_base
= ((char *) ub
->data
) + offset
;
125 iov
[0].iov_len
= ub
->len
- offset
;
126 msghdr
.msg_iovlen
= 1;
130 ret
= sendmsg(fd
, &msghdr
, 0);
131 } while (ret
< 0 && errno
== EINTR
);
136 void ubus_msg_list_free(struct ubus_msg_buf_list
*ubl
)
138 list_del_init(&ubl
->list
);
139 ubus_msg_free(ubl
->msg
);
143 static void ubus_msg_enqueue(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
)
145 struct ubus_msg_buf_list
*ubl
;
147 if (cl
->txq_len
+ ub
->len
> UBUS_CLIENT_MAX_TXQ_LEN
)
150 ubl
= calloc(1, sizeof(struct ubus_msg_buf_list
));
154 INIT_LIST_HEAD(&ubl
->list
);
155 ubl
->msg
= ubus_msg_ref(ub
);
157 list_add_tail(&cl
->tx_queue
, &ubl
->list
);
158 cl
->txq_len
+= ub
->len
;
161 /* takes the msgbuf reference */
162 void ubus_msg_send(struct ubus_client
*cl
, struct ubus_msg_buf
*ub
)
166 if (ub
->hdr
.type
!= UBUS_MSG_MONITOR
)
167 ubusd_monitor_message(cl
, ub
, true);
169 if (list_empty(&cl
->tx_queue
)) {
170 written
= ubus_msg_writev(cl
->sock
.fd
, ub
, 0);
175 if (written
>= (ssize_t
) (ub
->len
+ sizeof(ub
->hdr
)))
178 cl
->txq_ofs
= written
;
179 cl
->txq_len
= -written
;
181 /* get an event once we can write to the socket again */
182 uloop_fd_add(&cl
->sock
, ULOOP_READ
| ULOOP_WRITE
| ULOOP_EDGE_TRIGGER
);
184 ubus_msg_enqueue(cl
, ub
);