xref: /openbsd-src/usr.sbin/iscsid/control.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
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