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