ubusd: attempt to create socket folder
[project/ubus.git] / ubusd_main.c
1 /*
2 * Copyright (C) 2011-2014 Felix Fietkau <nbd@openwrt.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 */
6
7 #include <sys/socket.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #ifdef FreeBSD
11 #include <sys/param.h>
12 #endif
13 #include <string.h>
14 #include <syslog.h>
15
16 #include <libubox/usock.h>
17
18 #include "ubusd.h"
19
20 static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl)
21 {
22 return cl->tx_queue[cl->txq_cur];
23 }
24
25 static void ubus_msg_dequeue(struct ubus_client *cl)
26 {
27 struct ubus_msg_buf *ub = ubus_msg_head(cl);
28
29 if (!ub)
30 return;
31
32 ubus_msg_free(ub);
33 cl->txq_ofs = 0;
34 cl->tx_queue[cl->txq_cur] = NULL;
35 cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue);
36 }
37
38 static void handle_client_disconnect(struct ubus_client *cl)
39 {
40 while (ubus_msg_head(cl))
41 ubus_msg_dequeue(cl);
42
43 ubusd_monitor_disconnect(cl);
44 ubusd_proto_free_client(cl);
45 if (cl->pending_msg_fd >= 0)
46 close(cl->pending_msg_fd);
47 uloop_fd_delete(&cl->sock);
48 close(cl->sock.fd);
49 free(cl);
50 }
51
52 static void client_cb(struct uloop_fd *sock, unsigned int events)
53 {
54 struct ubus_client *cl = container_of(sock, struct ubus_client, sock);
55 uint8_t fd_buf[CMSG_SPACE(sizeof(int))] = { 0 };
56 struct msghdr msghdr = { 0 };
57 struct ubus_msg_buf *ub;
58 static struct iovec iov;
59 struct cmsghdr *cmsg;
60 int *pfd;
61
62 msghdr.msg_iov = &iov,
63 msghdr.msg_iovlen = 1,
64 msghdr.msg_control = fd_buf;
65 msghdr.msg_controllen = sizeof(fd_buf);
66
67 cmsg = CMSG_FIRSTHDR(&msghdr);
68 cmsg->cmsg_type = SCM_RIGHTS;
69 cmsg->cmsg_level = SOL_SOCKET;
70 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
71
72 pfd = (int *) CMSG_DATA(cmsg);
73 msghdr.msg_controllen = cmsg->cmsg_len;
74
75 /* first try to tx more pending data */
76 while ((ub = ubus_msg_head(cl))) {
77 ssize_t written;
78
79 written = ubus_msg_writev(sock->fd, ub, cl->txq_ofs);
80 if (written < 0) {
81 switch(errno) {
82 case EINTR:
83 case EAGAIN:
84 break;
85 default:
86 goto disconnect;
87 }
88 break;
89 }
90
91 cl->txq_ofs += written;
92 if (cl->txq_ofs < ub->len + sizeof(ub->hdr))
93 break;
94
95 ubus_msg_dequeue(cl);
96 }
97
98 /* prevent further ULOOP_WRITE events if we don't have data
99 * to send anymore */
100 if (!ubus_msg_head(cl) && (events & ULOOP_WRITE))
101 uloop_fd_add(sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
102
103 retry:
104 if (!sock->eof && cl->pending_msg_offset < (int) sizeof(cl->hdrbuf)) {
105 int offset = cl->pending_msg_offset;
106 int bytes;
107
108 *pfd = -1;
109
110 iov.iov_base = ((char *) &cl->hdrbuf) + offset;
111 iov.iov_len = sizeof(cl->hdrbuf) - offset;
112
113 if (cl->pending_msg_fd < 0) {
114 msghdr.msg_control = fd_buf;
115 msghdr.msg_controllen = cmsg->cmsg_len;
116 } else {
117 msghdr.msg_control = NULL;
118 msghdr.msg_controllen = 0;
119 }
120
121 bytes = recvmsg(sock->fd, &msghdr, 0);
122 if (bytes < 0)
123 goto out;
124
125 if (*pfd >= 0)
126 cl->pending_msg_fd = *pfd;
127
128 cl->pending_msg_offset += bytes;
129 if (cl->pending_msg_offset < (int) sizeof(cl->hdrbuf))
130 goto out;
131
132 if (blob_pad_len(&cl->hdrbuf.data) > UBUS_MAX_MSGLEN)
133 goto disconnect;
134
135 cl->pending_msg = ubus_msg_new(NULL, blob_raw_len(&cl->hdrbuf.data), false);
136 if (!cl->pending_msg)
137 goto disconnect;
138
139 cl->hdrbuf.hdr.seq = be16_to_cpu(cl->hdrbuf.hdr.seq);
140 cl->hdrbuf.hdr.peer = be32_to_cpu(cl->hdrbuf.hdr.peer);
141
142 memcpy(&cl->pending_msg->hdr, &cl->hdrbuf.hdr, sizeof(cl->hdrbuf.hdr));
143 memcpy(cl->pending_msg->data, &cl->hdrbuf.data, sizeof(cl->hdrbuf.data));
144 }
145
146 ub = cl->pending_msg;
147 if (ub) {
148 int offset = cl->pending_msg_offset - sizeof(ub->hdr);
149 int len = blob_raw_len(ub->data) - offset;
150 int bytes = 0;
151
152 if (len > 0) {
153 bytes = read(sock->fd, (char *) ub->data + offset, len);
154 if (bytes <= 0)
155 goto out;
156 }
157
158 if (bytes < len) {
159 cl->pending_msg_offset += bytes;
160 goto out;
161 }
162
163 /* accept message */
164 ub->fd = cl->pending_msg_fd;
165 cl->pending_msg_fd = -1;
166 cl->pending_msg_offset = 0;
167 cl->pending_msg = NULL;
168 ubusd_monitor_message(cl, ub, false);
169 ubusd_proto_receive_message(cl, ub);
170 goto retry;
171 }
172
173 out:
174 if (!sock->eof || ubus_msg_head(cl))
175 return;
176
177 disconnect:
178 handle_client_disconnect(cl);
179 }
180
181 static bool get_next_connection(int fd)
182 {
183 struct ubus_client *cl;
184 int client_fd;
185
186 client_fd = accept(fd, NULL, 0);
187 if (client_fd < 0) {
188 switch (errno) {
189 case ECONNABORTED:
190 case EINTR:
191 return true;
192 default:
193 return false;
194 }
195 }
196
197 cl = ubusd_proto_new_client(client_fd, client_cb);
198 if (cl)
199 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_EDGE_TRIGGER);
200 else
201 close(client_fd);
202
203 return true;
204 }
205
206 static void server_cb(struct uloop_fd *fd, unsigned int events)
207 {
208 bool next;
209
210 do {
211 next = get_next_connection(fd->fd);
212 } while (next);
213 }
214
215 static struct uloop_fd server_fd = {
216 .cb = server_cb,
217 };
218
219 static int usage(const char *progname)
220 {
221 fprintf(stderr, "Usage: %s [<options>]\n"
222 "Options: \n"
223 " -A <path>: Set the path to ACL files\n"
224 " -s <socket>: Set the unix domain socket to listen on\n"
225 "\n", progname);
226 return 1;
227 }
228
229 static void sighup_handler(int sig)
230 {
231 ubusd_acl_load();
232 }
233
234 static void mkdir_sockdir()
235 {
236 char *ubus_sock_dir, *tmp;
237
238 ubus_sock_dir = strdup(UBUS_UNIX_SOCKET);
239 tmp = strrchr(ubus_sock_dir, '/');
240 if (tmp) {
241 *tmp = '\0';
242 mkdir(ubus_sock_dir, 0755);
243 }
244 free(ubus_sock_dir);
245 }
246
247 int main(int argc, char **argv)
248 {
249 const char *ubus_socket = UBUS_UNIX_SOCKET;
250 int ret = 0;
251 int ch;
252
253 signal(SIGPIPE, SIG_IGN);
254 signal(SIGHUP, sighup_handler);
255
256 openlog("ubusd", LOG_PID, LOG_DAEMON);
257 uloop_init();
258
259 while ((ch = getopt(argc, argv, "A:s:")) != -1) {
260 switch (ch) {
261 case 's':
262 ubus_socket = optarg;
263 break;
264 case 'A':
265 ubusd_acl_dir = optarg;
266 break;
267 default:
268 return usage(argv[0]);
269 }
270 }
271
272 mkdir_sockdir();
273 unlink(ubus_socket);
274 umask(0111);
275 server_fd.fd = usock(USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK, ubus_socket, NULL);
276 if (server_fd.fd < 0) {
277 perror("usock");
278 ret = -1;
279 goto out;
280 }
281 uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
282 ubusd_acl_load();
283
284 uloop_run();
285 unlink(ubus_socket);
286
287 out:
288 uloop_done();
289 return ret;
290 }