• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ubus/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 }
272 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt