remove some duplication
[project/ubus.git] / ubusd.c
1 #include <sys/socket.h>
2 #include <sys/uio.h>
3 #include <signal.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7
8 #include <libubox/blob.h>
9 #include <libubox/uloop.h>
10 #include <libubox/usock.h>
11 #include <libubox/list.h>
12
13 #include "ubusd.h"
14
15 static struct ubus_msg_buf *ubus_msg_unshare(struct ubus_msg_buf *ub)
16 {
17         ub = realloc(ub, sizeof(*ub) + ub->len);
18         if (!ub)
19                 return NULL;
20
21         ub->refcount = 1;
22         memcpy(ub + 1, ub->data, ub->len);
23         ub->data = (void *) (ub + 1);
24         return ub;
25 }
26
27 static struct ubus_msg_buf *ubus_msg_ref(struct ubus_msg_buf *ub)
28 {
29         if (ub->refcount == ~0)
30                 return ubus_msg_unshare(ub);
31
32         ub->refcount++;
33         return ub;
34 }
35
36 struct ubus_msg_buf *ubus_msg_new(void *data, int len, bool shared)
37 {
38         struct ubus_msg_buf *ub;
39         int buflen = sizeof(*ub);
40
41         if (!shared)
42                 buflen += len;
43
44         ub = calloc(1, buflen);
45         if (!ub)
46                 return NULL;
47
48         if (shared) {
49                 ub->refcount = ~0;
50                 ub->data = data;
51         } else {
52                 ub->refcount = 1;
53                 ub->data = (void *) (ub + 1);
54                 if (data)
55                         memcpy(ub + 1, data, len);
56         }
57
58         ub->len = len;
59         return ub;
60 }
61
62 void ubus_msg_free(struct ubus_msg_buf *ub)
63 {
64         switch (ub->refcount) {
65         case 1:
66         case ~0:
67                 free(ub);
68                 break;
69         default:
70                 ub->refcount--;
71                 break;
72         }
73 }
74
75 static int ubus_msg_writev(int fd, struct ubus_msg_buf *ub, int offset)
76 {
77         struct iovec iov[2];
78
79         if (offset < sizeof(ub->hdr)) {
80                 iov[0].iov_base = ((char *) &ub->hdr) + offset;
81                 iov[0].iov_len = sizeof(ub->hdr) - offset;
82                 iov[1].iov_base = (char *) ub->data;
83                 iov[1].iov_len = ub->len;
84                 return writev(fd, iov, 2);
85         } else {
86                 offset -= sizeof(ub->hdr);
87                 return write(fd, ((char *) ub->data) + offset, ub->len - offset);
88         }
89 }
90
91 static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub)
92 {
93         if (cl->tx_queue[cl->txq_tail])
94                 return;
95
96         cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub);
97         cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue);
98 }
99
100 /* takes the msgbuf reference */
101 void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub, bool free)
102 {
103         int written;
104
105         if (!cl->tx_queue[cl->txq_cur]) {
106                 written = ubus_msg_writev(cl->sock.fd, ub, 0);
107                 if (written >= ub->len + sizeof(ub->hdr))
108                         goto out;
109
110                 if (written < 0)
111                         written = 0;
112
113                 cl->txq_ofs = written;
114
115                 /* get an event once we can write to the socket again */
116                 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
117         }
118         ubus_msg_enqueue(cl, ub);
119
120 out:
121         if (free)
122                 ubus_msg_free(ub);
123 }
124
125 static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl)
126 {
127         return cl->tx_queue[cl->txq_cur];
128 }
129
130 static void ubus_msg_dequeue(struct ubus_client *cl)
131 {
132         struct ubus_msg_buf *ub = ubus_msg_head(cl);
133
134         if (!ub)
135                 return;
136
137         ubus_msg_free(ub);
138         cl->txq_ofs = 0;
139         cl->tx_queue[cl->txq_cur] = NULL;
140         cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue);
141 }
142
143 static void handle_client_disconnect(struct ubus_client *cl)
144 {
145         while (ubus_msg_head(cl))
146                 ubus_msg_dequeue(cl);
147
148         ubusd_proto_free_client(cl);
149         uloop_fd_delete(&cl->sock);
150         close(cl->sock.fd);
151         free(cl);
152 }
153
154 static void client_cb(struct uloop_fd *sock, unsigned int events)
155 {
156         struct ubus_client *cl = container_of(sock, struct ubus_client, sock);
157         struct ubus_msg_buf *ub;
158
159         /* first try to tx more pending data */
160         while ((ub = ubus_msg_head(cl))) {
161                 int written;
162
163                 written = ubus_msg_writev(sock->fd, ub, cl->txq_ofs);
164                 if (written < 0) {
165                         switch(errno) {
166                         case EINTR:
167                         case EAGAIN:
168                                 break;
169                         default:
170                                 goto disconnect;
171                         }
172                         break;
173                 }
174
175                 cl->txq_ofs += written;
176                 if (cl->txq_ofs < ub->len + sizeof(ub->hdr))
177                         break;
178
179                 ubus_msg_dequeue(cl);
180         }
181
182         /* prevent further ULOOP_WRITE events if we don't have data
183          * to send anymore */
184         if (!ubus_msg_head(cl) && (events & ULOOP_WRITE))
185                 uloop_fd_add(sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
186
187 retry:
188         if (!sock->eof && cl->pending_msg_offset < sizeof(cl->hdrbuf)) {
189                 int offset = cl->pending_msg_offset;
190                 int bytes;
191
192                 bytes = read(sock->fd, (char *)&cl->hdrbuf + offset, sizeof(cl->hdrbuf) - offset);
193                 if (bytes < 0)
194                         goto out;
195
196                 cl->pending_msg_offset += bytes;
197                 if (cl->pending_msg_offset < sizeof(cl->hdrbuf))
198                         goto out;
199
200                 if (blob_pad_len(&cl->hdrbuf.data) > UBUS_MAX_MSGLEN)
201                         goto disconnect;
202
203                 cl->pending_msg = ubus_msg_new(NULL, blob_raw_len(&cl->hdrbuf.data), false);
204                 if (!cl->pending_msg)
205                         goto disconnect;
206
207                 memcpy(&cl->pending_msg->hdr, &cl->hdrbuf.hdr, sizeof(cl->hdrbuf.hdr));
208                 memcpy(cl->pending_msg->data, &cl->hdrbuf.data, sizeof(cl->hdrbuf.data));
209         }
210
211         ub = cl->pending_msg;
212         if (ub) {
213                 int offset = cl->pending_msg_offset - sizeof(ub->hdr);
214                 int len = blob_raw_len(ub->data) - offset;
215                 int bytes = 0;
216
217                 if (len > 0) {
218                         bytes = read(sock->fd, (char *) ub->data + offset, len);
219                         if (bytes <= 0)
220                                 goto out;
221                 }
222
223                 if (bytes < len) {
224                         cl->pending_msg_offset += bytes;
225                         goto out;
226                 }
227
228                 /* accept message */
229                 cl->pending_msg_offset = 0;
230                 cl->pending_msg = NULL;
231                 ubusd_proto_receive_message(cl, ub);
232                 goto retry;
233         }
234
235 out:
236         if (!sock->eof || ubus_msg_head(cl))
237                 return;
238
239 disconnect:
240         handle_client_disconnect(cl);
241 }
242
243 static bool get_next_connection(int fd)
244 {
245         struct ubus_client *cl;
246         int client_fd;
247
248         client_fd = accept(fd, NULL, 0);
249         if (client_fd < 0) {
250                 switch (errno) {
251                 case ECONNABORTED:
252                 case EINTR:
253                         return true;
254                 default:
255                         return false;
256                 }
257         }
258
259         cl = ubusd_proto_new_client(client_fd, client_cb);
260         if (cl)
261                 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
262         else
263                 close(client_fd);
264
265         return true;
266 }
267
268 static void server_cb(struct uloop_fd *fd, unsigned int events)
269 {
270         bool next;
271
272         do {
273                 next = get_next_connection(fd->fd);
274         } while (next);
275 }
276
277 static struct uloop_fd server_fd = {
278         .cb = server_cb,
279 };
280
281 static int usage(const char *progname)
282 {
283         fprintf(stderr, "Usage: %s [<options>]\n"
284                 "Options: \n"
285                 "  -s <socket>:         Set the unix domain socket to listen on\n"
286                 "\n", progname);
287         return 1;
288 }
289
290 int main(int argc, char **argv)
291 {
292         const char *ubus_socket = UBUS_UNIX_SOCKET;
293         int ret = 0;
294         int ch;
295
296         signal(SIGPIPE, SIG_IGN);
297
298         uloop_init();
299
300         while ((ch = getopt(argc, argv, "s:")) != -1) {
301                 switch (ch) {
302                 case 's':
303                         ubus_socket = optarg;
304                         break;
305                 default:
306                         return usage(argv[0]);
307                 }
308         }
309
310         unlink(ubus_socket);
311         server_fd.fd = usock(USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK, ubus_socket, NULL);
312         if (server_fd.fd < 0) {
313                 perror("usock");
314                 ret = -1;
315                 goto out;
316         }
317         uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
318
319         uloop_run();
320         unlink(ubus_socket);
321
322 out:
323         uloop_done();
324         return ret;
325 }