cli: do not use default timeout for listen
[project/ubus.git] / ubusd.c
1 /*
2  * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org>
3  *
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
7  *
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.
12  */
13
14 #include <sys/socket.h>
15 #include <sys/stat.h>
16 #include <sys/uio.h>
17 #ifdef FreeBSD
18 #include <sys/param.h>
19 #endif
20 #include <syslog.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #include <libubox/blob.h>
27 #include <libubox/uloop.h>
28 #include <libubox/usock.h>
29 #include <libubox/list.h>
30
31 #include "ubusd.h"
32
33 static struct ubus_msg_buf *ubus_msg_ref(struct ubus_msg_buf *ub)
34 {
35         struct ubus_msg_buf *new_ub;
36         if (ub->refcount == ~0) {
37                 new_ub = ubus_msg_new(ub->data, ub->len, false);
38                 if (!new_ub)
39                         return NULL;
40                 memcpy(&new_ub->hdr, &ub->hdr, sizeof(struct ubus_msghdr));
41                 new_ub->fd = ub->fd;
42                 return new_ub;
43         }
44
45         ub->refcount++;
46         return ub;
47 }
48
49 struct ubus_msg_buf *ubus_msg_new(void *data, int len, bool shared)
50 {
51         struct ubus_msg_buf *ub;
52         int buflen = sizeof(*ub);
53
54         if (!shared)
55                 buflen += len;
56
57         ub = calloc(1, buflen);
58         if (!ub)
59                 return NULL;
60
61         ub->fd = -1;
62
63         if (shared) {
64                 ub->refcount = ~0;
65                 ub->data = data;
66         } else {
67                 ub->refcount = 1;
68                 ub->data = (void *) (ub + 1);
69                 if (data)
70                         memcpy(ub + 1, data, len);
71         }
72
73         ub->len = len;
74         return ub;
75 }
76
77 void ubus_msg_free(struct ubus_msg_buf *ub)
78 {
79         switch (ub->refcount) {
80         case 1:
81         case ~0:
82                 if (ub->fd >= 0)
83                         close(ub->fd);
84
85                 free(ub);
86                 break;
87         default:
88                 ub->refcount--;
89                 break;
90         }
91 }
92
93 static int ubus_msg_writev(int fd, struct ubus_msg_buf *ub, int offset)
94 {
95         static struct iovec iov[2];
96         static struct {
97                 struct cmsghdr h;
98                 int fd;
99         } fd_buf = {
100                 .h = {
101                         .cmsg_len = sizeof(fd_buf),
102                         .cmsg_level = SOL_SOCKET,
103                         .cmsg_type = SCM_RIGHTS,
104                 },
105         };
106         struct msghdr msghdr = {
107                 .msg_iov = iov,
108                 .msg_iovlen = ARRAY_SIZE(iov),
109                 .msg_control = &fd_buf,
110                 .msg_controllen = sizeof(fd_buf),
111         };
112
113         fd_buf.fd = ub->fd;
114         if (ub->fd < 0) {
115                 msghdr.msg_control = NULL;
116                 msghdr.msg_controllen = 0;
117         }
118
119         if (offset < sizeof(ub->hdr)) {
120                 struct ubus_msghdr hdr;
121
122                 hdr.version = ub->hdr.version;
123                 hdr.type = ub->hdr.type;
124                 hdr.seq = cpu_to_be16(ub->hdr.seq);
125                 hdr.peer = cpu_to_be32(ub->hdr.peer);
126
127                 iov[0].iov_base = ((char *) &hdr) + offset;
128                 iov[0].iov_len = sizeof(hdr) - offset;
129                 iov[1].iov_base = (char *) ub->data;
130                 iov[1].iov_len = ub->len;
131
132                 return sendmsg(fd, &msghdr, 0);
133         } else {
134                 offset -= sizeof(ub->hdr);
135                 return write(fd, ((char *) ub->data) + offset, ub->len - offset);
136         }
137 }
138
139 static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub)
140 {
141         if (cl->tx_queue[cl->txq_tail])
142                 return;
143
144         cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub);
145         cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue);
146 }
147
148 /* takes the msgbuf reference */
149 void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub, bool free)
150 {
151         int written;
152
153         if (ub->hdr.type != UBUS_MSG_MONITOR)
154                 ubusd_monitor_message(cl, ub, true);
155
156         if (!cl->tx_queue[cl->txq_cur]) {
157                 written = ubus_msg_writev(cl->sock.fd, ub, 0);
158
159                 if (written < 0)
160                         written = 0;
161
162                 if (written >= ub->len + sizeof(ub->hdr))
163                         goto out;
164
165                 cl->txq_ofs = written;
166
167                 /* get an event once we can write to the socket again */
168                 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
169         }
170         ubus_msg_enqueue(cl, ub);
171
172 out:
173         if (free)
174                 ubus_msg_free(ub);
175 }
176
177 static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl)
178 {
179         return cl->tx_queue[cl->txq_cur];
180 }
181
182 static void ubus_msg_dequeue(struct ubus_client *cl)
183 {
184         struct ubus_msg_buf *ub = ubus_msg_head(cl);
185
186         if (!ub)
187                 return;
188
189         ubus_msg_free(ub);
190         cl->txq_ofs = 0;
191         cl->tx_queue[cl->txq_cur] = NULL;
192         cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue);
193 }
194
195 static void handle_client_disconnect(struct ubus_client *cl)
196 {
197         while (ubus_msg_head(cl))
198                 ubus_msg_dequeue(cl);
199
200         ubusd_monitor_disconnect(cl);
201         ubusd_proto_free_client(cl);
202         if (cl->pending_msg_fd >= 0)
203                 close(cl->pending_msg_fd);
204         uloop_fd_delete(&cl->sock);
205         close(cl->sock.fd);
206         free(cl);
207 }
208
209 static void client_cb(struct uloop_fd *sock, unsigned int events)
210 {
211         struct ubus_client *cl = container_of(sock, struct ubus_client, sock);
212         struct ubus_msg_buf *ub;
213         static struct iovec iov;
214         static struct {
215                 struct cmsghdr h;
216                 int fd;
217         } fd_buf = {
218                 .h = {
219                         .cmsg_type = SCM_RIGHTS,
220                         .cmsg_level = SOL_SOCKET,
221                         .cmsg_len = sizeof(fd_buf),
222                 }
223         };
224         struct msghdr msghdr = {
225                 .msg_iov = &iov,
226                 .msg_iovlen = 1,
227         };
228
229         /* first try to tx more pending data */
230         while ((ub = ubus_msg_head(cl))) {
231                 int written;
232
233                 written = ubus_msg_writev(sock->fd, ub, cl->txq_ofs);
234                 if (written < 0) {
235                         switch(errno) {
236                         case EINTR:
237                         case EAGAIN:
238                                 break;
239                         default:
240                                 goto disconnect;
241                         }
242                         break;
243                 }
244
245                 cl->txq_ofs += written;
246                 if (cl->txq_ofs < ub->len + sizeof(ub->hdr))
247                         break;
248
249                 ubus_msg_dequeue(cl);
250         }
251
252         /* prevent further ULOOP_WRITE events if we don't have data
253          * to send anymore */
254         if (!ubus_msg_head(cl) && (events & ULOOP_WRITE))
255                 uloop_fd_add(sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
256
257 retry:
258         if (!sock->eof && cl->pending_msg_offset < sizeof(cl->hdrbuf)) {
259                 int offset = cl->pending_msg_offset;
260                 int bytes;
261
262                 fd_buf.fd = -1;
263
264                 iov.iov_base = ((char *) &cl->hdrbuf) + offset;
265                 iov.iov_len = sizeof(cl->hdrbuf) - offset;
266
267                 if (cl->pending_msg_fd < 0) {
268                         msghdr.msg_control = &fd_buf;
269                         msghdr.msg_controllen = sizeof(fd_buf);
270                 } else {
271                         msghdr.msg_control = NULL;
272                         msghdr.msg_controllen = 0;
273                 }
274
275                 bytes = recvmsg(sock->fd, &msghdr, 0);
276                 if (bytes < 0)
277                         goto out;
278
279                 if (fd_buf.fd >= 0)
280                         cl->pending_msg_fd = fd_buf.fd;
281
282                 cl->pending_msg_offset += bytes;
283                 if (cl->pending_msg_offset < sizeof(cl->hdrbuf))
284                         goto out;
285
286                 if (blob_pad_len(&cl->hdrbuf.data) > UBUS_MAX_MSGLEN)
287                         goto disconnect;
288
289                 cl->pending_msg = ubus_msg_new(NULL, blob_raw_len(&cl->hdrbuf.data), false);
290                 if (!cl->pending_msg)
291                         goto disconnect;
292
293                 cl->hdrbuf.hdr.seq = be16_to_cpu(cl->hdrbuf.hdr.seq);
294                 cl->hdrbuf.hdr.peer = be32_to_cpu(cl->hdrbuf.hdr.peer);
295
296                 memcpy(&cl->pending_msg->hdr, &cl->hdrbuf.hdr, sizeof(cl->hdrbuf.hdr));
297                 memcpy(cl->pending_msg->data, &cl->hdrbuf.data, sizeof(cl->hdrbuf.data));
298         }
299
300         ub = cl->pending_msg;
301         if (ub) {
302                 int offset = cl->pending_msg_offset - sizeof(ub->hdr);
303                 int len = blob_raw_len(ub->data) - offset;
304                 int bytes = 0;
305
306                 if (len > 0) {
307                         bytes = read(sock->fd, (char *) ub->data + offset, len);
308                         if (bytes <= 0)
309                                 goto out;
310                 }
311
312                 if (bytes < len) {
313                         cl->pending_msg_offset += bytes;
314                         goto out;
315                 }
316
317                 /* accept message */
318                 ub->fd = cl->pending_msg_fd;
319                 cl->pending_msg_fd = -1;
320                 cl->pending_msg_offset = 0;
321                 cl->pending_msg = NULL;
322                 ubusd_monitor_message(cl, ub, false);
323                 ubusd_proto_receive_message(cl, ub);
324                 goto retry;
325         }
326
327 out:
328         if (!sock->eof || ubus_msg_head(cl))
329                 return;
330
331 disconnect:
332         handle_client_disconnect(cl);
333 }
334
335 static bool get_next_connection(int fd)
336 {
337         struct ubus_client *cl;
338         int client_fd;
339
340         client_fd = accept(fd, NULL, 0);
341         if (client_fd < 0) {
342                 switch (errno) {
343                 case ECONNABORTED:
344                 case EINTR:
345                         return true;
346                 default:
347                         return false;
348                 }
349         }
350
351         cl = ubusd_proto_new_client(client_fd, client_cb);
352         if (cl)
353                 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
354         else
355                 close(client_fd);
356
357         return true;
358 }
359
360 static void server_cb(struct uloop_fd *fd, unsigned int events)
361 {
362         bool next;
363
364         do {
365                 next = get_next_connection(fd->fd);
366         } while (next);
367 }
368
369 static struct uloop_fd server_fd = {
370         .cb = server_cb,
371 };
372
373 static int usage(const char *progname)
374 {
375         fprintf(stderr, "Usage: %s [<options>]\n"
376                 "Options: \n"
377                 "  -A <path>:           Set the path to ACL files\n"
378                 "  -s <socket>:         Set the unix domain socket to listen on\n"
379                 "\n", progname);
380         return 1;
381 }
382
383 static void sighup_handler(int sig)
384 {
385         ubusd_acl_load();
386 }
387
388 int main(int argc, char **argv)
389 {
390         const char *ubus_socket = UBUS_UNIX_SOCKET;
391         int ret = 0;
392         int ch;
393
394         signal(SIGPIPE, SIG_IGN);
395         signal(SIGHUP, sighup_handler);
396
397         openlog("ubusd", LOG_PID, LOG_DAEMON);
398         uloop_init();
399
400         while ((ch = getopt(argc, argv, "A:s:")) != -1) {
401                 switch (ch) {
402                 case 's':
403                         ubus_socket = optarg;
404                         break;
405                 case 'A':
406                         ubusd_acl_dir = optarg;
407                         break;
408                 default:
409                         return usage(argv[0]);
410                 }
411         }
412
413         unlink(ubus_socket);
414         umask(0111);
415         server_fd.fd = usock(USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK, ubus_socket, NULL);
416         if (server_fd.fd < 0) {
417                 perror("usock");
418                 ret = -1;
419                 goto out;
420         }
421         uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
422         ubusd_acl_load();
423
424         uloop_run();
425         unlink(ubus_socket);
426
427 out:
428         uloop_done();
429         return ret;
430 }