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

Sources/ubus/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 #ifdef FreeBSD
 16 #include <sys/param.h>
 17 #endif
 18 
 19 #include "ubusd.h"
 20 
 21 #define USES_EXTERNAL_BUFFER ~0U
 22 
 23 static struct ubus_msg_buf *ubus_msg_ref(struct ubus_msg_buf *ub)
 24 {
 25         struct ubus_msg_buf *new_ub;
 26         if (ub->refcount == USES_EXTERNAL_BUFFER) {
 27                 new_ub = ubus_msg_new(ub->data, ub->len, false);
 28                 if (!new_ub)
 29                         return NULL;
 30                 memcpy(&new_ub->hdr, &ub->hdr, sizeof(struct ubus_msghdr));
 31                 new_ub->fd = ub->fd;
 32                 return new_ub;
 33         }
 34 
 35         ub->refcount++;
 36         return ub;
 37 }
 38 
 39 struct ubus_msg_buf *ubus_msg_new(void *data, int len, bool shared)
 40 {
 41         struct ubus_msg_buf *ub;
 42         int buflen = sizeof(*ub);
 43 
 44         if (!shared)
 45                 buflen += len;
 46 
 47         ub = calloc(1, buflen);
 48         if (!ub)
 49                 return NULL;
 50 
 51         ub->fd = -1;
 52 
 53         if (shared) {
 54                 ub->refcount = USES_EXTERNAL_BUFFER;
 55                 ub->data = data;
 56         } else {
 57                 ub->refcount = 1;
 58                 ub->data = (void *) (ub + 1);
 59                 if (data)
 60                         memcpy(ub + 1, data, len);
 61         }
 62 
 63         ub->len = len;
 64         return ub;
 65 }
 66 
 67 void ubus_msg_free(struct ubus_msg_buf *ub)
 68 {
 69         switch (ub->refcount) {
 70         case 1:
 71         case USES_EXTERNAL_BUFFER:
 72                 if (ub->fd >= 0)
 73                         close(ub->fd);
 74 
 75                 free(ub);
 76                 break;
 77         default:
 78                 ub->refcount--;
 79                 break;
 80         }
 81 }
 82 
 83 ssize_t ubus_msg_writev(int fd, struct ubus_msg_buf *ub, size_t offset)
 84 {
 85         static struct iovec iov[2];
 86         static struct {
 87                 int fd;
 88                 struct cmsghdr h;
 89         } fd_buf = {
 90                 .h = {
 91                         .cmsg_len = sizeof(fd_buf),
 92                         .cmsg_level = SOL_SOCKET,
 93                         .cmsg_type = SCM_RIGHTS,
 94                 },
 95         };
 96         struct msghdr msghdr = {
 97                 .msg_iov = iov,
 98                 .msg_iovlen = ARRAY_SIZE(iov),
 99                 .msg_control = &fd_buf,
100                 .msg_controllen = sizeof(fd_buf),
101         };
102         struct ubus_msghdr hdr;
103         ssize_t ret;
104 
105         fd_buf.fd = ub->fd;
106         if (ub->fd < 0 || offset) {
107                 msghdr.msg_control = NULL;
108                 msghdr.msg_controllen = 0;
109         }
110 
111         if (offset < sizeof(ub->hdr)) {
112                 hdr.version = ub->hdr.version;
113                 hdr.type = ub->hdr.type;
114                 hdr.seq = cpu_to_be16(ub->hdr.seq);
115                 hdr.peer = cpu_to_be32(ub->hdr.peer);
116 
117                 iov[0].iov_base = ((char *) &hdr) + offset;
118                 iov[0].iov_len = sizeof(hdr) - offset;
119                 iov[1].iov_base = (char *) ub->data;
120                 iov[1].iov_len = ub->len;
121         } else {
122                 offset -= sizeof(ub->hdr);
123                 iov[0].iov_base = ((char *) ub->data) + offset;
124                 iov[0].iov_len = ub->len - offset;
125                 msghdr.msg_iovlen = 1;
126         }
127 
128         do {
129                 ret = sendmsg(fd, &msghdr, 0);
130         } while (ret < 0 && errno == EINTR);
131 
132         return ret;
133 }
134 
135 static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub)
136 {
137         if (cl->tx_queue[cl->txq_tail])
138                 return;
139 
140         cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub);
141         cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue);
142 }
143 
144 /* takes the msgbuf reference */
145 void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub)
146 {
147 <<<<<<< HEAD
148         if (ub->hdr.type != UBUS_MSG_MONITOR)
149                 ubusd_monitor_message(cl, ub, true);
150 
151 =======
152         ssize_t written;
153 
154         if (ub->hdr.type != UBUS_MSG_MONITOR)
155                 ubusd_monitor_message(cl, ub, true);
156 
157         if (!cl->tx_queue[cl->txq_cur]) {
158                 written = ubus_msg_writev(cl->sock.fd, ub, 0);
159 
160                 if (written < 0)
161                         written = 0;
162 
163                 if (written >= (ssize_t) (ub->len + sizeof(ub->hdr)))
164                         return;
165 
166                 cl->txq_ofs = written;
167 
168                 /* get an event once we can write to the socket again */
169                 uloop_fd_add(&cl->sock, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER);
170         }
171 >>>>>>> 8f2292478c5776dd7533a68f0a963b64d5dd92e3
172         ubus_msg_enqueue(cl, ub);
173         cl->sock.cb(&cl->sock, ULOOP_WRITE);
174 }
175 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt