1 /* $OpenBSD: control.c,v 1.8 2014/04/21 17:41:52 claudio 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 TAILQ_ENTRY(control) entry; 38 struct event ev; 39 struct pduq channel; 40 int fd; 41 }; 42 43 struct control_state { 44 struct event ev; 45 struct event evt; 46 int fd; 47 } *control_state; 48 49 TAILQ_HEAD(, control) controls; 50 51 #define CONTROL_BACKLOG 5 52 53 void control_accept(int, short, void *); 54 void control_close(struct control *); 55 void control_dispatch(int, short, void *); 56 struct pdu *control_getpdu(char *, size_t); 57 58 int 59 control_init(char *path) 60 { 61 struct sockaddr_un sun; 62 int fd; 63 mode_t old_umask; 64 65 if ((control_state = calloc(1, sizeof(*control_state))) == NULL) { 66 log_warn("control_init: calloc"); 67 return -1; 68 } 69 70 if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) == -1) { 71 log_warn("control_init: socket"); 72 return -1; 73 } 74 75 bzero(&sun, sizeof(sun)); 76 sun.sun_family = AF_UNIX; 77 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 78 sizeof(sun.sun_path)) { 79 log_warnx("control_init: path %s too long", path); 80 return -1; 81 } 82 83 if (unlink(path) == -1) 84 if (errno != ENOENT) { 85 log_warn("control_init: unlink %s", path); 86 close(fd); 87 return -1; 88 } 89 90 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 91 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 92 log_warn("control_init: bind: %s", path); 93 close(fd); 94 umask(old_umask); 95 return -1; 96 } 97 umask(old_umask); 98 99 if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 100 log_warn("control_init: chmod"); 101 close(fd); 102 (void)unlink(path); 103 return -1; 104 } 105 106 if (listen(fd, CONTROL_BACKLOG) == -1) { 107 log_warn("control_init: listen"); 108 close(fd); 109 (void)unlink(path); 110 return -1; 111 } 112 113 socket_setblockmode(fd, 1); 114 control_state->fd = fd; 115 TAILQ_INIT(&controls); 116 117 return 0; 118 } 119 120 void 121 control_cleanup(char *path) 122 { 123 struct control *c; 124 125 if (path) 126 unlink(path); 127 128 while ((c = TAILQ_FIRST(&controls)) != NULL) { 129 TAILQ_REMOVE(&controls, c, entry); 130 control_close(c); 131 } 132 event_del(&control_state->ev); 133 event_del(&control_state->evt); 134 close(control_state->fd); 135 free(control_state); 136 } 137 138 void 139 control_event_init(void) 140 { 141 event_set(&control_state->ev, control_state->fd, EV_READ, 142 control_accept, NULL); 143 event_add(&control_state->ev, NULL); 144 evtimer_set(&control_state->evt, control_accept, NULL); 145 } 146 147 /* ARGSUSED */ 148 void 149 control_accept(int listenfd, short event, void *bula) 150 { 151 int connfd; 152 socklen_t len; 153 struct sockaddr_un sun; 154 struct control *c; 155 156 event_add(&control_state->ev, NULL); 157 if ((event & EV_TIMEOUT)) 158 return; 159 160 len = sizeof(sun); 161 if ((connfd = accept(listenfd, 162 (struct sockaddr *)&sun, &len)) == -1) { 163 /* 164 * Pause accept if we are out of file descriptors, or 165 * libevent will haunt us here too. 166 */ 167 if (errno == ENFILE || errno == EMFILE) { 168 struct timeval evtpause = { 1, 0 }; 169 170 event_del(&control_state->ev); 171 evtimer_add(&control_state->evt, &evtpause); 172 } else if (errno != EWOULDBLOCK && errno != EINTR && 173 errno != ECONNABORTED) 174 log_warn("control_accept"); 175 return; 176 } 177 178 if ((c = malloc(sizeof(struct control))) == NULL) { 179 log_warn("control_accept"); 180 close(connfd); 181 return; 182 } 183 184 TAILQ_INIT(&c->channel); 185 c->fd = connfd; 186 event_set(&c->ev, connfd, EV_READ, control_dispatch, c); 187 event_add(&c->ev, NULL); 188 } 189 190 void 191 control_close(struct control *c) 192 { 193 event_del(&c->ev); 194 close(c->fd); 195 196 /* Some file descriptors are available again. */ 197 if (evtimer_pending(&control_state->evt, NULL)) { 198 evtimer_del(&control_state->evt); 199 event_add(&control_state->ev, NULL); 200 } 201 202 pdu_free_queue(&c->channel); 203 free(c); 204 } 205 206 static char cbuf[CONTROL_READ_SIZE]; 207 208 /* ARGSUSED */ 209 void 210 control_dispatch(int fd, short event, void *bula) 211 { 212 struct iovec iov[PDU_MAXIOV]; 213 struct msghdr msg; 214 struct control *c = bula; 215 struct pdu *pdu; 216 ssize_t n; 217 unsigned int niov = 0; 218 short flags = EV_READ; 219 220 if (event & EV_TIMEOUT) { 221 log_debug("control connection (fd %d) timed out.", fd); 222 control_close(c); 223 return; 224 } 225 if (event & EV_READ) { 226 if ((n = recv(fd, cbuf, sizeof(cbuf), 0)) == -1 && 227 !(errno == EAGAIN || errno == EINTR)) { 228 control_close(c); 229 return; 230 } 231 if (n == 0) { 232 control_close(c); 233 return; 234 } 235 pdu = control_getpdu(cbuf, n); 236 if (!pdu) { 237 log_debug("control connection (fd %d) bad msg.", fd); 238 control_close(c); 239 return; 240 } 241 iscsid_ctrl_dispatch(c, pdu); 242 } 243 if (event & EV_WRITE) { 244 if ((pdu = TAILQ_FIRST(&c->channel)) != NULL) { 245 for (niov = 0; niov < PDU_MAXIOV; niov++) { 246 iov[niov].iov_base = pdu->iov[niov].iov_base; 247 iov[niov].iov_len = pdu->iov[niov].iov_len; 248 } 249 bzero(&msg, sizeof(msg)); 250 msg.msg_iov = iov; 251 msg.msg_iovlen = niov; 252 if (sendmsg(fd, &msg, 0) == -1) { 253 if (errno == EAGAIN || errno == ENOBUFS) 254 goto requeue; 255 control_close(c); 256 return; 257 } 258 TAILQ_REMOVE(&c->channel, pdu, entry); 259 } 260 } 261 requeue: 262 if (!TAILQ_EMPTY(&c->channel)) 263 flags |= EV_WRITE; 264 265 event_del(&c->ev); 266 event_set(&c->ev, fd, flags, control_dispatch, c); 267 event_add(&c->ev, NULL); 268 } 269 270 struct pdu * 271 control_getpdu(char *buf, size_t len) 272 { 273 struct pdu *p; 274 struct ctrlmsghdr *cmh; 275 void *data; 276 size_t n; 277 int i; 278 279 if (len < sizeof(*cmh)) 280 return NULL; 281 282 if (!(p = pdu_new())) 283 return NULL; 284 285 n = sizeof(*cmh); 286 cmh = pdu_alloc(n); 287 memcpy(cmh, buf, n); 288 buf += n; 289 len -= n; 290 291 if (pdu_addbuf(p, cmh, n, 0)) { 292 free(cmh); 293 fail: 294 pdu_free(p); 295 return NULL; 296 } 297 298 for (i = 0; i < 3; i++) { 299 n = cmh->len[i]; 300 if (n == 0) 301 continue; 302 if (PDU_LEN(n) > len) 303 goto fail; 304 if (!(data = pdu_alloc(n))) 305 goto fail; 306 memcpy(data, buf, n); 307 if (pdu_addbuf(p, data, n, i + 1)) { 308 free(data); 309 goto fail; 310 } 311 buf += PDU_LEN(n); 312 len -= PDU_LEN(n); 313 } 314 315 return p; 316 } 317 318 void 319 control_queue(void *ch, struct pdu *pdu) 320 { 321 struct control *c = ch; 322 323 TAILQ_INSERT_TAIL(&c->channel, pdu, entry); 324 325 event_del(&c->ev); 326 event_set(&c->ev, c->fd, EV_READ|EV_WRITE, control_dispatch, c); 327 event_add(&c->ev, NULL); 328 } 329