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