1 /* $OpenBSD: control.c,v 1.10 2016/09/10 05:42:12 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/stat.h> 23 #include <sys/socket.h> 24 #include <sys/uio.h> 25 #include <sys/un.h> 26 #include <errno.h> 27 #include <event.h> 28 #include <fcntl.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "iscsid.h" 34 #include "log.h" 35 36 struct control { 37 struct event ev; 38 struct pduq channel; 39 int fd; 40 }; 41 42 struct control_state { 43 struct event ev; 44 struct event evt; 45 int fd; 46 } *control_state; 47 48 #define CONTROL_BACKLOG 5 49 50 void control_accept(int, short, void *); 51 void control_close(struct control *); 52 void control_dispatch(int, short, void *); 53 struct pdu *control_getpdu(char *, size_t); 54 55 int 56 control_init(char *path) 57 { 58 struct sockaddr_un sun; 59 int fd; 60 mode_t old_umask; 61 62 if ((control_state = calloc(1, sizeof(*control_state))) == NULL) { 63 log_warn("control_init: calloc"); 64 return -1; 65 } 66 67 if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1) { 68 log_warn("control_init: socket"); 69 return -1; 70 } 71 72 bzero(&sun, sizeof(sun)); 73 sun.sun_family = AF_UNIX; 74 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 75 sizeof(sun.sun_path)) { 76 log_warnx("control_init: path %s too long", path); 77 close(fd); 78 return -1; 79 } 80 81 if (unlink(path) == -1) 82 if (errno != ENOENT) { 83 log_warn("control_init: unlink %s", path); 84 close(fd); 85 return -1; 86 } 87 88 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 89 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 90 log_warn("control_init: bind: %s", path); 91 close(fd); 92 umask(old_umask); 93 return -1; 94 } 95 umask(old_umask); 96 97 if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 98 log_warn("control_init: chmod"); 99 close(fd); 100 (void)unlink(path); 101 return -1; 102 } 103 104 if (listen(fd, CONTROL_BACKLOG) == -1) { 105 log_warn("control_init: listen"); 106 close(fd); 107 (void)unlink(path); 108 return -1; 109 } 110 111 socket_setblockmode(fd, 1); 112 control_state->fd = fd; 113 114 return 0; 115 } 116 117 void 118 control_cleanup(char *path) 119 { 120 if (path) 121 unlink(path); 122 123 event_del(&control_state->ev); 124 event_del(&control_state->evt); 125 close(control_state->fd); 126 free(control_state); 127 } 128 129 void 130 control_event_init(void) 131 { 132 event_set(&control_state->ev, control_state->fd, EV_READ, 133 control_accept, NULL); 134 event_add(&control_state->ev, NULL); 135 evtimer_set(&control_state->evt, control_accept, NULL); 136 } 137 138 /* ARGSUSED */ 139 void 140 control_accept(int listenfd, short event, void *bula) 141 { 142 int connfd; 143 socklen_t len; 144 struct sockaddr_un sun; 145 struct control *c; 146 147 event_add(&control_state->ev, NULL); 148 if ((event & EV_TIMEOUT)) 149 return; 150 151 len = sizeof(sun); 152 if ((connfd = accept(listenfd, 153 (struct sockaddr *)&sun, &len)) == -1) { 154 /* 155 * Pause accept if we are out of file descriptors, or 156 * libevent will haunt us here too. 157 */ 158 if (errno == ENFILE || errno == EMFILE) { 159 struct timeval evtpause = { 1, 0 }; 160 161 event_del(&control_state->ev); 162 evtimer_add(&control_state->evt, &evtpause); 163 } else if (errno != EWOULDBLOCK && errno != EINTR && 164 errno != ECONNABORTED) 165 log_warn("control_accept"); 166 return; 167 } 168 169 if ((c = malloc(sizeof(struct control))) == NULL) { 170 log_warn("control_accept"); 171 close(connfd); 172 return; 173 } 174 175 TAILQ_INIT(&c->channel); 176 c->fd = connfd; 177 event_set(&c->ev, connfd, EV_READ, control_dispatch, c); 178 event_add(&c->ev, NULL); 179 } 180 181 void 182 control_close(struct control *c) 183 { 184 event_del(&c->ev); 185 close(c->fd); 186 187 /* Some file descriptors are available again. */ 188 if (evtimer_pending(&control_state->evt, NULL)) { 189 evtimer_del(&control_state->evt); 190 event_add(&control_state->ev, NULL); 191 } 192 193 pdu_free_queue(&c->channel); 194 free(c); 195 } 196 197 static char cbuf[CONTROL_READ_SIZE]; 198 199 /* ARGSUSED */ 200 void 201 control_dispatch(int fd, short event, void *bula) 202 { 203 struct iovec iov[PDU_MAXIOV]; 204 struct msghdr msg; 205 struct control *c = bula; 206 struct pdu *pdu; 207 ssize_t n; 208 unsigned int niov = 0; 209 short flags = EV_READ; 210 211 if (event & EV_TIMEOUT) { 212 log_debug("control connection (fd %d) timed out.", fd); 213 control_close(c); 214 return; 215 } 216 if (event & EV_READ) { 217 if ((n = recv(fd, cbuf, sizeof(cbuf), 0)) == -1 && 218 !(errno == EAGAIN || errno == EINTR)) { 219 control_close(c); 220 return; 221 } 222 if (n == 0) { 223 control_close(c); 224 return; 225 } 226 pdu = control_getpdu(cbuf, n); 227 if (!pdu) { 228 log_debug("control connection (fd %d) bad msg.", fd); 229 control_close(c); 230 return; 231 } 232 iscsid_ctrl_dispatch(c, pdu); 233 } 234 if (event & EV_WRITE) { 235 if ((pdu = TAILQ_FIRST(&c->channel)) != NULL) { 236 for (niov = 0; niov < PDU_MAXIOV; niov++) { 237 iov[niov].iov_base = pdu->iov[niov].iov_base; 238 iov[niov].iov_len = pdu->iov[niov].iov_len; 239 } 240 bzero(&msg, sizeof(msg)); 241 msg.msg_iov = iov; 242 msg.msg_iovlen = niov; 243 if (sendmsg(fd, &msg, 0) == -1) { 244 if (errno == EAGAIN || errno == ENOBUFS) 245 goto requeue; 246 control_close(c); 247 return; 248 } 249 TAILQ_REMOVE(&c->channel, pdu, entry); 250 } 251 } 252 requeue: 253 if (!TAILQ_EMPTY(&c->channel)) 254 flags |= EV_WRITE; 255 256 event_del(&c->ev); 257 event_set(&c->ev, fd, flags, control_dispatch, c); 258 event_add(&c->ev, NULL); 259 } 260 261 struct pdu * 262 control_getpdu(char *buf, size_t len) 263 { 264 struct pdu *p; 265 struct ctrlmsghdr *cmh; 266 void *data; 267 size_t n; 268 int i; 269 270 if (len < sizeof(*cmh)) 271 return NULL; 272 273 if (!(p = pdu_new())) 274 return NULL; 275 276 n = sizeof(*cmh); 277 cmh = pdu_alloc(n); 278 memcpy(cmh, buf, n); 279 buf += n; 280 len -= n; 281 282 if (pdu_addbuf(p, cmh, n, 0)) { 283 free(cmh); 284 fail: 285 pdu_free(p); 286 return NULL; 287 } 288 289 for (i = 0; i < 3; i++) { 290 n = cmh->len[i]; 291 if (n == 0) 292 continue; 293 if (PDU_LEN(n) > len) 294 goto fail; 295 if (!(data = pdu_alloc(n))) 296 goto fail; 297 memcpy(data, buf, n); 298 if (pdu_addbuf(p, data, n, i + 1)) { 299 free(data); 300 goto fail; 301 } 302 buf += PDU_LEN(n); 303 len -= PDU_LEN(n); 304 } 305 306 return p; 307 } 308 309 void 310 control_queue(void *ch, struct pdu *pdu) 311 { 312 struct control *c = ch; 313 314 TAILQ_INSERT_TAIL(&c->channel, pdu, entry); 315 316 event_del(&c->ev); 317 event_set(&c->ev, c->fd, EV_READ|EV_WRITE, control_dispatch, c); 318 event_add(&c->ev, NULL); 319 } 320