View | Details | Raw Unified | Return to bug 233699 | Differences between
and this patch

Collapse All | Expand All

(-)b/lib/libopenbsd/imsg-buffer.c (-8 / +11 lines)
Lines 1-309 Link Here
1
/*	$OpenBSD: imsg-buffer.c,v 1.7 2015/07/12 18:40:49 nicm Exp $	*/
1
/*	$OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $	*/
2
2
3
/*
3
/*
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5
 *
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
8
 * copyright notice and this permission notice appear in all copies.
9
 *
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 *
17
 *
18
 * $FreeBSD$
18
 * $FreeBSD$
19
 */
19
 */
20
20
21
#include <sys/types.h>
21
#include <sys/types.h>
22
#include <sys/queue.h>
22
#include <sys/queue.h>
23
#include <sys/socket.h>
23
#include <sys/socket.h>
24
#include <sys/uio.h>
24
#include <sys/uio.h>
25
25
26
#include <limits.h>
26
#include <limits.h>
27
#include <errno.h>
27
#include <errno.h>
28
#include <stdlib.h>
28
#include <stdlib.h>
29
#include <string.h>
29
#include <string.h>
30
#include <unistd.h>
30
#include <unistd.h>
31
31
32
#include "imsg.h"
32
#include "imsg.h"
33
33
34
int	ibuf_realloc(struct ibuf *, size_t);
34
static int	ibuf_realloc(struct ibuf *, size_t);
35
void	ibuf_enqueue(struct msgbuf *, struct ibuf *);
35
static void	ibuf_enqueue(struct msgbuf *, struct ibuf *);
36
void	ibuf_dequeue(struct msgbuf *, struct ibuf *);
36
static void	ibuf_dequeue(struct msgbuf *, struct ibuf *);
37
37
38
struct ibuf *
38
struct ibuf *
39
ibuf_open(size_t len)
39
ibuf_open(size_t len)
40
{
40
{
41
	struct ibuf	*buf;
41
	struct ibuf	*buf;
42
42
43
	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
43
	if ((buf = calloc(1, sizeof(struct ibuf))) == NULL)
44
		return (NULL);
44
		return (NULL);
45
	if ((buf->buf = malloc(len)) == NULL) {
45
	if ((buf->buf = malloc(len)) == NULL) {
46
		free(buf);
46
		free(buf);
47
		return (NULL);
47
		return (NULL);
48
	}
48
	}
49
	buf->size = buf->max = len;
49
	buf->size = buf->max = len;
50
	buf->fd = -1;
50
	buf->fd = -1;
51
51
52
	return (buf);
52
	return (buf);
53
}
53
}
54
54
55
struct ibuf *
55
struct ibuf *
56
ibuf_dynamic(size_t len, size_t max)
56
ibuf_dynamic(size_t len, size_t max)
57
{
57
{
58
	struct ibuf	*buf;
58
	struct ibuf	*buf;
59
59
60
	if (max < len)
60
	if (max < len)
61
		return (NULL);
61
		return (NULL);
62
62
63
	if ((buf = ibuf_open(len)) == NULL)
63
	if ((buf = ibuf_open(len)) == NULL)
64
		return (NULL);
64
		return (NULL);
65
65
66
	if (max > 0)
66
	if (max > 0)
67
		buf->max = max;
67
		buf->max = max;
68
68
69
	return (buf);
69
	return (buf);
70
}
70
}
71
71
72
int
72
static int
73
ibuf_realloc(struct ibuf *buf, size_t len)
73
ibuf_realloc(struct ibuf *buf, size_t len)
74
{
74
{
75
	u_char	*b;
75
	u_char	*b;
76
76
77
	/* on static buffers max is eq size and so the following fails */
77
	/* on static buffers max is eq size and so the following fails */
78
	if (buf->wpos + len > buf->max) {
78
	if (buf->wpos + len > buf->max) {
79
		errno = ERANGE;
79
		errno = ERANGE;
80
		return (-1);
80
		return (-1);
81
	}
81
	}
82
82
83
	b = realloc(buf->buf, buf->wpos + len);
83
	b = reallocarray(buf->buf, buf->wpos + len, 1);
84
	if (b == NULL)
84
	if (b == NULL)
85
		return (-1);
85
		return (-1);
86
	memset(b, 0, buf->wpos + len);
86
	buf->buf = b;
87
	buf->buf = b;
87
	buf->size = buf->wpos + len;
88
	buf->size = buf->wpos + len;
88
89
89
	return (0);
90
	return (0);
90
}
91
}
91
92
92
int
93
int
93
ibuf_add(struct ibuf *buf, const void *data, size_t len)
94
ibuf_add(struct ibuf *buf, const void *data, size_t len)
94
{
95
{
95
	if (buf->wpos + len > buf->size)
96
	if (buf->wpos + len > buf->size)
96
		if (ibuf_realloc(buf, len) == -1)
97
		if (ibuf_realloc(buf, len) == -1)
97
			return (-1);
98
			return (-1);
98
99
99
	memcpy(buf->buf + buf->wpos, data, len);
100
	memcpy(buf->buf + buf->wpos, data, len);
100
	buf->wpos += len;
101
	buf->wpos += len;
101
	return (0);
102
	return (0);
102
}
103
}
103
104
104
void *
105
void *
105
ibuf_reserve(struct ibuf *buf, size_t len)
106
ibuf_reserve(struct ibuf *buf, size_t len)
106
{
107
{
107
	void	*b;
108
	void	*b;
108
109
109
	if (buf->wpos + len > buf->size)
110
	if (buf->wpos + len > buf->size)
110
		if (ibuf_realloc(buf, len) == -1)
111
		if (ibuf_realloc(buf, len) == -1)
111
			return (NULL);
112
			return (NULL);
112
113
113
	b = buf->buf + buf->wpos;
114
	b = buf->buf + buf->wpos;
114
	buf->wpos += len;
115
	buf->wpos += len;
115
	return (b);
116
	return (b);
116
}
117
}
117
118
118
void *
119
void *
119
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
120
ibuf_seek(struct ibuf *buf, size_t pos, size_t len)
120
{
121
{
121
	/* only allowed to seek in already written parts */
122
	/* only allowed to seek in already written parts */
122
	if (pos + len > buf->wpos)
123
	if (pos + len > buf->wpos)
123
		return (NULL);
124
		return (NULL);
124
125
125
	return (buf->buf + pos);
126
	return (buf->buf + pos);
126
}
127
}
127
128
128
size_t
129
size_t
129
ibuf_size(struct ibuf *buf)
130
ibuf_size(struct ibuf *buf)
130
{
131
{
131
	return (buf->wpos);
132
	return (buf->wpos);
132
}
133
}
133
134
134
size_t
135
size_t
135
ibuf_left(struct ibuf *buf)
136
ibuf_left(struct ibuf *buf)
136
{
137
{
137
	return (buf->max - buf->wpos);
138
	return (buf->max - buf->wpos);
138
}
139
}
139
140
140
void
141
void
141
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
142
ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf)
142
{
143
{
143
	ibuf_enqueue(msgbuf, buf);
144
	ibuf_enqueue(msgbuf, buf);
144
}
145
}
145
146
146
int
147
int
147
ibuf_write(struct msgbuf *msgbuf)
148
ibuf_write(struct msgbuf *msgbuf)
148
{
149
{
149
	struct iovec	 iov[IOV_MAX];
150
	struct iovec	 iov[IOV_MAX];
150
	struct ibuf	*buf;
151
	struct ibuf	*buf;
151
	unsigned int	 i = 0;
152
	unsigned int	 i = 0;
152
	ssize_t	n;
153
	ssize_t	n;
153
154
154
	memset(&iov, 0, sizeof(iov));
155
	memset(&iov, 0, sizeof(iov));
155
	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
156
	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
156
		if (i >= IOV_MAX)
157
		if (i >= IOV_MAX)
157
			break;
158
			break;
158
		iov[i].iov_base = buf->buf + buf->rpos;
159
		iov[i].iov_base = buf->buf + buf->rpos;
159
		iov[i].iov_len = buf->wpos - buf->rpos;
160
		iov[i].iov_len = buf->wpos - buf->rpos;
160
		i++;
161
		i++;
161
	}
162
	}
162
163
163
again:
164
again:
164
	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
165
	if ((n = writev(msgbuf->fd, iov, i)) == -1) {
165
		if (errno == EINTR)
166
		if (errno == EINTR)
166
			goto again;
167
			goto again;
167
		if (errno == ENOBUFS)
168
		if (errno == ENOBUFS)
168
			errno = EAGAIN;
169
			errno = EAGAIN;
169
		return (-1);
170
		return (-1);
170
	}
171
	}
171
172
172
	if (n == 0) {			/* connection closed */
173
	if (n == 0) {			/* connection closed */
173
		errno = 0;
174
		errno = 0;
174
		return (0);
175
		return (0);
175
	}
176
	}
176
177
177
	msgbuf_drain(msgbuf, n);
178
	msgbuf_drain(msgbuf, n);
178
179
179
	return (1);
180
	return (1);
180
}
181
}
181
182
182
void
183
void
183
ibuf_free(struct ibuf *buf)
184
ibuf_free(struct ibuf *buf)
184
{
185
{
186
	if (buf == NULL)
187
		return;
185
	free(buf->buf);
188
	free(buf->buf);
186
	free(buf);
189
	free(buf);
187
}
190
}
188
191
189
void
192
void
190
msgbuf_init(struct msgbuf *msgbuf)
193
msgbuf_init(struct msgbuf *msgbuf)
191
{
194
{
192
	msgbuf->queued = 0;
195
	msgbuf->queued = 0;
193
	msgbuf->fd = -1;
196
	msgbuf->fd = -1;
194
	TAILQ_INIT(&msgbuf->bufs);
197
	TAILQ_INIT(&msgbuf->bufs);
195
}
198
}
196
199
197
void
200
void
198
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
201
msgbuf_drain(struct msgbuf *msgbuf, size_t n)
199
{
202
{
200
	struct ibuf	*buf, *next;
203
	struct ibuf	*buf, *next;
201
204
202
	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
205
	for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0;
203
	    buf = next) {
206
	    buf = next) {
204
		next = TAILQ_NEXT(buf, entry);
207
		next = TAILQ_NEXT(buf, entry);
205
		if (buf->rpos + n >= buf->wpos) {
208
		if (buf->rpos + n >= buf->wpos) {
206
			n -= buf->wpos - buf->rpos;
209
			n -= buf->wpos - buf->rpos;
207
			ibuf_dequeue(msgbuf, buf);
210
			ibuf_dequeue(msgbuf, buf);
208
		} else {
211
		} else {
209
			buf->rpos += n;
212
			buf->rpos += n;
210
			n = 0;
213
			n = 0;
211
		}
214
		}
212
	}
215
	}
213
}
216
}
214
217
215
void
218
void
216
msgbuf_clear(struct msgbuf *msgbuf)
219
msgbuf_clear(struct msgbuf *msgbuf)
217
{
220
{
218
	struct ibuf	*buf;
221
	struct ibuf	*buf;
219
222
220
	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
223
	while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL)
221
		ibuf_dequeue(msgbuf, buf);
224
		ibuf_dequeue(msgbuf, buf);
222
}
225
}
223
226
224
int
227
int
225
msgbuf_write(struct msgbuf *msgbuf)
228
msgbuf_write(struct msgbuf *msgbuf)
226
{
229
{
227
	struct iovec	 iov[IOV_MAX];
230
	struct iovec	 iov[IOV_MAX];
228
	struct ibuf	*buf;
231
	struct ibuf	*buf;
229
	unsigned int	 i = 0;
232
	unsigned int	 i = 0;
230
	ssize_t		 n;
233
	ssize_t		 n;
231
	struct msghdr	 msg;
234
	struct msghdr	 msg;
232
	struct cmsghdr	*cmsg;
235
	struct cmsghdr	*cmsg;
233
	union {
236
	union {
234
		struct cmsghdr	hdr;
237
		struct cmsghdr	hdr;
235
		char		buf[CMSG_SPACE(sizeof(int))];
238
		char		buf[CMSG_SPACE(sizeof(int))];
236
	} cmsgbuf;
239
	} cmsgbuf;
237
240
238
	memset(&iov, 0, sizeof(iov));
241
	memset(&iov, 0, sizeof(iov));
239
	memset(&msg, 0, sizeof(msg));
242
	memset(&msg, 0, sizeof(msg));
240
	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
243
	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
241
	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
244
	TAILQ_FOREACH(buf, &msgbuf->bufs, entry) {
242
		if (i >= IOV_MAX)
245
		if (i >= IOV_MAX)
243
			break;
246
			break;
244
		iov[i].iov_base = buf->buf + buf->rpos;
247
		iov[i].iov_base = buf->buf + buf->rpos;
245
		iov[i].iov_len = buf->wpos - buf->rpos;
248
		iov[i].iov_len = buf->wpos - buf->rpos;
246
		i++;
249
		i++;
247
		if (buf->fd != -1)
250
		if (buf->fd != -1)
248
			break;
251
			break;
249
	}
252
	}
250
253
251
	msg.msg_iov = iov;
254
	msg.msg_iov = iov;
252
	msg.msg_iovlen = i;
255
	msg.msg_iovlen = i;
253
256
254
	if (buf != NULL && buf->fd != -1) {
257
	if (buf != NULL && buf->fd != -1) {
255
		msg.msg_control = (caddr_t)&cmsgbuf.buf;
258
		msg.msg_control = (caddr_t)&cmsgbuf.buf;
256
		msg.msg_controllen = sizeof(cmsgbuf.buf);
259
		msg.msg_controllen = sizeof(cmsgbuf.buf);
257
		cmsg = CMSG_FIRSTHDR(&msg);
260
		cmsg = CMSG_FIRSTHDR(&msg);
258
		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
261
		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
259
		cmsg->cmsg_level = SOL_SOCKET;
262
		cmsg->cmsg_level = SOL_SOCKET;
260
		cmsg->cmsg_type = SCM_RIGHTS;
263
		cmsg->cmsg_type = SCM_RIGHTS;
261
		*(int *)CMSG_DATA(cmsg) = buf->fd;
264
		*(int *)CMSG_DATA(cmsg) = buf->fd;
262
	}
265
	}
263
266
264
again:
267
again:
265
	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
268
	if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) {
266
		if (errno == EINTR)
269
		if (errno == EINTR)
267
			goto again;
270
			goto again;
268
		if (errno == ENOBUFS)
271
		if (errno == ENOBUFS)
269
			errno = EAGAIN;
272
			errno = EAGAIN;
270
		return (-1);
273
		return (-1);
271
	}
274
	}
272
275
273
	if (n == 0) {			/* connection closed */
276
	if (n == 0) {			/* connection closed */
274
		errno = 0;
277
		errno = 0;
275
		return (0);
278
		return (0);
276
	}
279
	}
277
280
278
	/*
281
	/*
279
	 * assumption: fd got sent if sendmsg sent anything
282
	 * assumption: fd got sent if sendmsg sent anything
280
	 * this works because fds are passed one at a time
283
	 * this works because fds are passed one at a time
281
	 */
284
	 */
282
	if (buf != NULL && buf->fd != -1) {
285
	if (buf != NULL && buf->fd != -1) {
283
		close(buf->fd);
286
		close(buf->fd);
284
		buf->fd = -1;
287
		buf->fd = -1;
285
	}
288
	}
286
289
287
	msgbuf_drain(msgbuf, n);
290
	msgbuf_drain(msgbuf, n);
288
291
289
	return (1);
292
	return (1);
290
}
293
}
291
294
292
void
295
static void
293
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
296
ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf)
294
{
297
{
295
	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
298
	TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry);
296
	msgbuf->queued++;
299
	msgbuf->queued++;
297
}
300
}
298
301
299
void
302
static void
300
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
303
ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf)
301
{
304
{
302
	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
305
	TAILQ_REMOVE(&msgbuf->bufs, buf, entry);
303
306
304
	if (buf->fd != -1)
307
	if (buf->fd != -1)
305
		close(buf->fd);
308
		close(buf->fd);
306
309
307
	msgbuf->queued--;
310
	msgbuf->queued--;
308
	ibuf_free(buf);
311
	ibuf_free(buf);
309
}
312
}
(-)b/lib/libopenbsd/imsg.c (-13 / +11 lines)
Lines 1-304 Link Here
1
/*	$OpenBSD: imsg.c,v 1.13 2015/12/09 11:54:12 tb Exp $	*/
1
/*	$OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $	*/
2
2
3
/*
3
/*
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
4
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5
 *
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
8
 * copyright notice and this permission notice appear in all copies.
9
 *
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 *
18
 * $FreeBSD$
19
 */
17
 */
20
18
21
#include <sys/types.h>
19
#include <sys/types.h>
22
#include <sys/queue.h>
20
#include <sys/queue.h>
23
#include <sys/socket.h>
21
#include <sys/socket.h>
24
#include <sys/uio.h>
22
#include <sys/uio.h>
25
23
26
#include <errno.h>
24
#include <errno.h>
27
#include <stdlib.h>
25
#include <stdlib.h>
28
#include <string.h>
26
#include <string.h>
29
#include <unistd.h>
27
#include <unistd.h>
30
28
31
#include "imsg.h"
29
#include "imsg.h"
32
30
33
int	 imsg_fd_overhead = 0;
31
int	 imsg_fd_overhead = 0;
34
32
35
int	 imsg_get_fd(struct imsgbuf *);
33
static int	 imsg_get_fd(struct imsgbuf *);
36
34
37
void
35
void
38
imsg_init(struct imsgbuf *ibuf, int fd)
36
imsg_init(struct imsgbuf *ibuf, int fd)
39
{
37
{
40
	msgbuf_init(&ibuf->w);
38
	msgbuf_init(&ibuf->w);
41
	memset(&ibuf->r, 0, sizeof(ibuf->r));
39
	memset(&ibuf->r, 0, sizeof(ibuf->r));
42
	ibuf->fd = fd;
40
	ibuf->fd = fd;
43
	ibuf->w.fd = fd;
41
	ibuf->w.fd = fd;
44
	ibuf->pid = getpid();
42
	ibuf->pid = getpid();
45
	TAILQ_INIT(&ibuf->fds);
43
	TAILQ_INIT(&ibuf->fds);
46
}
44
}
47
45
48
ssize_t
46
ssize_t
49
imsg_read(struct imsgbuf *ibuf)
47
imsg_read(struct imsgbuf *ibuf)
50
{
48
{
51
	struct msghdr		 msg;
49
	struct msghdr		 msg;
52
	struct cmsghdr		*cmsg;
50
	struct cmsghdr		*cmsg;
53
	union {
51
	union {
54
		struct cmsghdr hdr;
52
		struct cmsghdr hdr;
55
		char	buf[CMSG_SPACE(sizeof(int) * 1)];
53
		char	buf[CMSG_SPACE(sizeof(int) * 1)];
56
	} cmsgbuf;
54
	} cmsgbuf;
57
	struct iovec		 iov;
55
	struct iovec		 iov;
58
	ssize_t			 n = -1;
56
	ssize_t			 n = -1;
59
	int			 fd;
57
	int			 fd;
60
	struct imsg_fd		*ifd;
58
	struct imsg_fd		*ifd;
61
59
62
	memset(&msg, 0, sizeof(msg));
60
	memset(&msg, 0, sizeof(msg));
63
	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
61
	memset(&cmsgbuf, 0, sizeof(cmsgbuf));
64
62
65
	iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
63
	iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
66
	iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
64
	iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
67
	msg.msg_iov = &iov;
65
	msg.msg_iov = &iov;
68
	msg.msg_iovlen = 1;
66
	msg.msg_iovlen = 1;
69
	msg.msg_control = &cmsgbuf.buf;
67
	msg.msg_control = &cmsgbuf.buf;
70
	msg.msg_controllen = sizeof(cmsgbuf.buf);
68
	msg.msg_controllen = sizeof(cmsgbuf.buf);
71
69
72
	if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
70
	if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
73
		return (-1);
71
		return (-1);
74
72
75
again:
73
again:
76
	if (getdtablecount() + imsg_fd_overhead +
74
	if (getdtablecount() + imsg_fd_overhead +
77
	    (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
75
	    (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
78
	    >= getdtablesize()) {
76
	    >= getdtablesize()) {
79
		errno = EAGAIN;
77
		errno = EAGAIN;
80
		free(ifd);
78
		free(ifd);
81
		return (-1);
79
		return (-1);
82
	}
80
	}
83
81
84
	if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
82
	if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
85
		if (errno == EINTR)
83
		if (errno == EINTR)
86
			goto again;
84
			goto again;
87
		goto fail;
85
		goto fail;
88
	}
86
	}
89
87
90
	ibuf->r.wpos += n;
88
	ibuf->r.wpos += n;
91
89
92
	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
90
	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
93
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
91
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
94
		if (cmsg->cmsg_level == SOL_SOCKET &&
92
		if (cmsg->cmsg_level == SOL_SOCKET &&
95
		    cmsg->cmsg_type == SCM_RIGHTS) {
93
		    cmsg->cmsg_type == SCM_RIGHTS) {
96
			int i;
94
			int i;
97
			int j;
95
			int j;
98
96
99
			/*
97
			/*
100
			 * We only accept one file descriptor.  Due to C
98
			 * We only accept one file descriptor.  Due to C
101
			 * padding rules, our control buffer might contain
99
			 * padding rules, our control buffer might contain
102
			 * more than one fd, and we must close them.
100
			 * more than one fd, and we must close them.
103
			 */
101
			 */
104
			j = ((char *)cmsg + cmsg->cmsg_len -
102
			j = ((char *)cmsg + cmsg->cmsg_len -
105
			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
103
			    (char *)CMSG_DATA(cmsg)) / sizeof(int);
106
			for (i = 0; i < j; i++) {
104
			for (i = 0; i < j; i++) {
107
				fd = ((int *)CMSG_DATA(cmsg))[i];
105
				fd = ((int *)CMSG_DATA(cmsg))[i];
108
				if (ifd != NULL) {
106
				if (ifd != NULL) {
109
					ifd->fd = fd;
107
					ifd->fd = fd;
110
					TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
108
					TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
111
					    entry);
109
					    entry);
112
					ifd = NULL;
110
					ifd = NULL;
113
				} else
111
				} else
114
					close(fd);
112
					close(fd);
115
			}
113
			}
116
		}
114
		}
117
		/* we do not handle other ctl data level */
115
		/* we do not handle other ctl data level */
118
	}
116
	}
119
117
120
fail:
118
fail:
121
	free(ifd);
119
	free(ifd);
122
	return (n);
120
	return (n);
123
}
121
}
124
122
125
ssize_t
123
ssize_t
126
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
124
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
127
{
125
{
128
	size_t			 av, left, datalen;
126
	size_t			 av, left, datalen;
129
127
130
	av = ibuf->r.wpos;
128
	av = ibuf->r.wpos;
131
129
132
	if (IMSG_HEADER_SIZE > av)
130
	if (IMSG_HEADER_SIZE > av)
133
		return (0);
131
		return (0);
134
132
135
	memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
133
	memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
136
	if (imsg->hdr.len < IMSG_HEADER_SIZE ||
134
	if (imsg->hdr.len < IMSG_HEADER_SIZE ||
137
	    imsg->hdr.len > MAX_IMSGSIZE) {
135
	    imsg->hdr.len > MAX_IMSGSIZE) {
138
		errno = ERANGE;
136
		errno = ERANGE;
139
		return (-1);
137
		return (-1);
140
	}
138
	}
141
	if (imsg->hdr.len > av)
139
	if (imsg->hdr.len > av)
142
		return (0);
140
		return (0);
143
	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
141
	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
144
	ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
142
	ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
145
	if (datalen == 0)
143
	if (datalen == 0)
146
		imsg->data = NULL;
144
		imsg->data = NULL;
147
	else if ((imsg->data = malloc(datalen)) == NULL)
145
	else if ((imsg->data = malloc(datalen)) == NULL)
148
		return (-1);
146
		return (-1);
149
147
150
	if (imsg->hdr.flags & IMSGF_HASFD)
148
	if (imsg->hdr.flags & IMSGF_HASFD)
151
		imsg->fd = imsg_get_fd(ibuf);
149
		imsg->fd = imsg_get_fd(ibuf);
152
	else
150
	else
153
		imsg->fd = -1;
151
		imsg->fd = -1;
154
152
155
	memcpy(imsg->data, ibuf->r.rptr, datalen);
153
	memcpy(imsg->data, ibuf->r.rptr, datalen);
156
154
157
	if (imsg->hdr.len < av) {
155
	if (imsg->hdr.len < av) {
158
		left = av - imsg->hdr.len;
156
		left = av - imsg->hdr.len;
159
		memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
157
		memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
160
		ibuf->r.wpos = left;
158
		ibuf->r.wpos = left;
161
	} else
159
	} else
162
		ibuf->r.wpos = 0;
160
		ibuf->r.wpos = 0;
163
161
164
	return (datalen + IMSG_HEADER_SIZE);
162
	return (datalen + IMSG_HEADER_SIZE);
165
}
163
}
166
164
167
int
165
int
168
imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
166
imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
169
    pid_t pid, int fd, const void *data, u_int16_t datalen)
167
    int fd, const void *data, uint16_t datalen)
170
{
168
{
171
	struct ibuf	*wbuf;
169
	struct ibuf	*wbuf;
172
170
173
	if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
171
	if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
174
		return (-1);
172
		return (-1);
175
173
176
	if (imsg_add(wbuf, data, datalen) == -1)
174
	if (imsg_add(wbuf, data, datalen) == -1)
177
		return (-1);
175
		return (-1);
178
176
179
	wbuf->fd = fd;
177
	wbuf->fd = fd;
180
178
181
	imsg_close(ibuf, wbuf);
179
	imsg_close(ibuf, wbuf);
182
180
183
	return (1);
181
	return (1);
184
}
182
}
185
183
186
int
184
int
187
imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
185
imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
188
    pid_t pid, int fd, const struct iovec *iov, int iovcnt)
186
    int fd, const struct iovec *iov, int iovcnt)
189
{
187
{
190
	struct ibuf	*wbuf;
188
	struct ibuf	*wbuf;
191
	int		 i, datalen = 0;
189
	int		 i, datalen = 0;
192
190
193
	for (i = 0; i < iovcnt; i++)
191
	for (i = 0; i < iovcnt; i++)
194
		datalen += iov[i].iov_len;
192
		datalen += iov[i].iov_len;
195
193
196
	if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
194
	if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
197
		return (-1);
195
		return (-1);
198
196
199
	for (i = 0; i < iovcnt; i++)
197
	for (i = 0; i < iovcnt; i++)
200
		if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
198
		if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
201
			return (-1);
199
			return (-1);
202
200
203
	wbuf->fd = fd;
201
	wbuf->fd = fd;
204
202
205
	imsg_close(ibuf, wbuf);
203
	imsg_close(ibuf, wbuf);
206
204
207
	return (1);
205
	return (1);
208
}
206
}
209
207
210
/* ARGSUSED */
208
/* ARGSUSED */
211
struct ibuf *
209
struct ibuf *
212
imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid,
210
imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
213
    pid_t pid, u_int16_t datalen)
211
    uint16_t datalen)
214
{
212
{
215
	struct ibuf	*wbuf;
213
	struct ibuf	*wbuf;
216
	struct imsg_hdr	 hdr;
214
	struct imsg_hdr	 hdr;
217
215
218
	datalen += IMSG_HEADER_SIZE;
216
	datalen += IMSG_HEADER_SIZE;
219
	if (datalen > MAX_IMSGSIZE) {
217
	if (datalen > MAX_IMSGSIZE) {
220
		errno = ERANGE;
218
		errno = ERANGE;
221
		return (NULL);
219
		return (NULL);
222
	}
220
	}
223
221
224
	hdr.type = type;
222
	hdr.type = type;
225
	hdr.flags = 0;
223
	hdr.flags = 0;
226
	hdr.peerid = peerid;
224
	hdr.peerid = peerid;
227
	if ((hdr.pid = pid) == 0)
225
	if ((hdr.pid = pid) == 0)
228
		hdr.pid = ibuf->pid;
226
		hdr.pid = ibuf->pid;
229
	if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
227
	if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
230
		return (NULL);
228
		return (NULL);
231
	}
229
	}
232
	if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
230
	if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
233
		return (NULL);
231
		return (NULL);
234
232
235
	return (wbuf);
233
	return (wbuf);
236
}
234
}
237
235
238
int
236
int
239
imsg_add(struct ibuf *msg, const void *data, u_int16_t datalen)
237
imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
240
{
238
{
241
	if (datalen)
239
	if (datalen)
242
		if (ibuf_add(msg, data, datalen) == -1) {
240
		if (ibuf_add(msg, data, datalen) == -1) {
243
			ibuf_free(msg);
241
			ibuf_free(msg);
244
			return (-1);
242
			return (-1);
245
		}
243
		}
246
	return (datalen);
244
	return (datalen);
247
}
245
}
248
246
249
void
247
void
250
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
248
imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
251
{
249
{
252
	struct imsg_hdr	*hdr;
250
	struct imsg_hdr	*hdr;
253
251
254
	hdr = (struct imsg_hdr *)msg->buf;
252
	hdr = (struct imsg_hdr *)msg->buf;
255
253
256
	hdr->flags &= ~IMSGF_HASFD;
254
	hdr->flags &= ~IMSGF_HASFD;
257
	if (msg->fd != -1)
255
	if (msg->fd != -1)
258
		hdr->flags |= IMSGF_HASFD;
256
		hdr->flags |= IMSGF_HASFD;
259
257
260
	hdr->len = (u_int16_t)msg->wpos;
258
	hdr->len = (uint16_t)msg->wpos;
261
259
262
	ibuf_close(&ibuf->w, msg);
260
	ibuf_close(&ibuf->w, msg);
263
}
261
}
264
262
265
void
263
void
266
imsg_free(struct imsg *imsg)
264
imsg_free(struct imsg *imsg)
267
{
265
{
268
	free(imsg->data);
266
	free(imsg->data);
269
}
267
}
270
268
271
int
269
static int
272
imsg_get_fd(struct imsgbuf *ibuf)
270
imsg_get_fd(struct imsgbuf *ibuf)
273
{
271
{
274
	int		 fd;
272
	int		 fd;
275
	struct imsg_fd	*ifd;
273
	struct imsg_fd	*ifd;
276
274
277
	if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
275
	if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
278
		return (-1);
276
		return (-1);
279
277
280
	fd = ifd->fd;
278
	fd = ifd->fd;
281
	TAILQ_REMOVE(&ibuf->fds, ifd, entry);
279
	TAILQ_REMOVE(&ibuf->fds, ifd, entry);
282
	free(ifd);
280
	free(ifd);
283
281
284
	return (fd);
282
	return (fd);
285
}
283
}
286
284
287
int
285
int
288
imsg_flush(struct imsgbuf *ibuf)
286
imsg_flush(struct imsgbuf *ibuf)
289
{
287
{
290
	while (ibuf->w.queued)
288
	while (ibuf->w.queued)
291
		if (msgbuf_write(&ibuf->w) <= 0)
289
		if (msgbuf_write(&ibuf->w) <= 0)
292
			return (-1);
290
			return (-1);
293
	return (0);
291
	return (0);
294
}
292
}
295
293
296
void
294
void
297
imsg_clear(struct imsgbuf *ibuf)
295
imsg_clear(struct imsgbuf *ibuf)
298
{
296
{
299
	int	fd;
297
	int	fd;
300
298
301
	msgbuf_clear(&ibuf->w);
299
	msgbuf_clear(&ibuf->w);
302
	while ((fd = imsg_get_fd(ibuf)) != -1)
300
	while ((fd = imsg_get_fd(ibuf)) != -1)
303
		close(fd);
301
		close(fd);
304
}
302
}

Return to bug 233699