2 /* $OpenBSD: imsg-buffer.c,v 1.3 2010/05/26 13:56:07 nicm Exp $ */
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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.
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.
20 #include <sys/param.h>
21 #include <sys/socket.h>
32 int ibuf_realloc(struct ibuf
*, size_t);
33 void ibuf_enqueue(struct msgbuf
*, struct ibuf
*);
34 void ibuf_dequeue(struct msgbuf
*, struct ibuf
*);
41 if ((buf
= calloc(1, sizeof(struct ibuf
))) == NULL
)
43 if ((buf
->buf
= malloc(len
)) == NULL
) {
47 buf
->size
= buf
->max
= len
;
54 ibuf_dynamic(size_t len
, size_t max
)
61 if ((buf
= ibuf_open(len
)) == NULL
)
71 ibuf_realloc(struct ibuf
*buf
, size_t len
)
75 /* on static buffers max is eq size and so the following fails */
76 if (buf
->wpos
+ len
> buf
->max
) {
81 b
= realloc(buf
->buf
, buf
->wpos
+ len
);
85 buf
->size
= buf
->wpos
+ len
;
91 ibuf_add(struct ibuf
*buf
, const void *data
, size_t len
)
93 if (buf
->wpos
+ len
> buf
->size
)
94 if (ibuf_realloc(buf
, len
) == -1)
97 memcpy(buf
->buf
+ buf
->wpos
, data
, len
);
103 ibuf_reserve(struct ibuf
*buf
, size_t len
)
107 if (buf
->wpos
+ len
> buf
->size
)
108 if (ibuf_realloc(buf
, len
) == -1)
111 b
= buf
->buf
+ buf
->wpos
;
117 ibuf_seek(struct ibuf
*buf
, size_t pos
, size_t len
)
119 /* only allowed to seek in already written parts */
120 if (pos
+ len
> buf
->wpos
)
123 return (buf
->buf
+ pos
);
127 ibuf_size(struct ibuf
*buf
)
133 ibuf_left(struct ibuf
*buf
)
135 return (buf
->max
- buf
->wpos
);
139 ibuf_close(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
141 ibuf_enqueue(msgbuf
, buf
);
145 ibuf_write(struct msgbuf
*msgbuf
)
147 struct iovec iov
[IOV_MAX
];
152 bzero(&iov
, sizeof(iov
));
153 TAILQ_FOREACH(buf
, &msgbuf
->bufs
, entry
) {
156 iov
[i
].iov_base
= buf
->buf
+ buf
->rpos
;
157 iov
[i
].iov_len
= buf
->wpos
- buf
->rpos
;
161 if ((n
= writev(msgbuf
->fd
, iov
, i
)) == -1) {
162 if (errno
== EAGAIN
|| errno
== ENOBUFS
||
163 errno
== EINTR
) /* try later */
169 if (n
== 0) { /* connection closed */
174 msgbuf_drain(msgbuf
, n
);
180 ibuf_free(struct ibuf
*buf
)
187 msgbuf_init(struct msgbuf
*msgbuf
)
191 TAILQ_INIT(&msgbuf
->bufs
);
195 msgbuf_drain(struct msgbuf
*msgbuf
, size_t n
)
197 struct ibuf
*buf
, *next
;
199 for (buf
= TAILQ_FIRST(&msgbuf
->bufs
); buf
!= NULL
&& n
> 0;
201 next
= TAILQ_NEXT(buf
, entry
);
202 if (buf
->rpos
+ n
>= buf
->wpos
) {
203 n
-= buf
->wpos
- buf
->rpos
;
204 ibuf_dequeue(msgbuf
, buf
);
213 msgbuf_clear(struct msgbuf
*msgbuf
)
217 while ((buf
= TAILQ_FIRST(&msgbuf
->bufs
)) != NULL
)
218 ibuf_dequeue(msgbuf
, buf
);
222 msgbuf_write(struct msgbuf
*msgbuf
)
224 struct iovec iov
[IOV_MAX
];
229 struct cmsghdr
*cmsg
;
232 char buf
[CMSG_SPACE(sizeof(int))];
235 bzero(&iov
, sizeof(iov
));
236 bzero(&msg
, sizeof(msg
));
237 TAILQ_FOREACH(buf
, &msgbuf
->bufs
, entry
) {
240 iov
[i
].iov_base
= buf
->buf
+ buf
->rpos
;
241 iov
[i
].iov_len
= buf
->wpos
- buf
->rpos
;
250 if (buf
!= NULL
&& buf
->fd
!= -1) {
251 msg
.msg_control
= (caddr_t
)&cmsgbuf
.buf
;
252 msg
.msg_controllen
= CMSG_SPACE(sizeof(int));
253 cmsg
= CMSG_FIRSTHDR(&msg
);
254 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
255 cmsg
->cmsg_level
= SOL_SOCKET
;
256 cmsg
->cmsg_type
= SCM_RIGHTS
;
257 *(int *)CMSG_DATA(cmsg
) = buf
->fd
;
260 if ((n
= sendmsg(msgbuf
->fd
, &msg
, 0)) == -1) {
261 if (errno
== EAGAIN
|| errno
== ENOBUFS
||
262 errno
== EINTR
) /* try later */
268 if (n
== 0) { /* connection closed */
274 * assumption: fd got sent if sendmsg sent anything
275 * this works because fds are passed one at a time
277 if (buf
!= NULL
&& buf
->fd
!= -1) {
282 msgbuf_drain(msgbuf
, n
);
288 ibuf_enqueue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
290 TAILQ_INSERT_TAIL(&msgbuf
->bufs
, buf
, entry
);
295 ibuf_dequeue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
297 TAILQ_REMOVE(&msgbuf
->bufs
, buf
, entry
);