]>
git.proxmox.com Git - mirror_frr.git/blob - lib/imsg-buffer.c
1 // SPDX-License-Identifier: ISC
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
13 static int ibuf_realloc(struct ibuf
*, size_t);
14 static void ibuf_enqueue(struct msgbuf
*, struct ibuf
*);
15 static void ibuf_dequeue(struct msgbuf
*, struct ibuf
*);
17 struct ibuf
*ibuf_open(size_t len
)
21 if ((buf
= calloc(1, sizeof(struct ibuf
))) == NULL
)
23 if ((buf
->buf
= malloc(len
)) == NULL
) {
27 buf
->size
= buf
->max
= len
;
33 struct ibuf
*ibuf_dynamic(size_t len
, size_t max
)
40 if ((buf
= ibuf_open(len
)) == NULL
)
49 static int ibuf_realloc(struct ibuf
*buf
, size_t len
)
53 /* on static buffers max is eq size and so the following fails */
54 if (buf
->wpos
+ len
> buf
->max
) {
59 b
= realloc(buf
->buf
, buf
->wpos
+ len
);
63 buf
->size
= buf
->wpos
+ len
;
68 int ibuf_add(struct ibuf
*buf
, const void *data
, size_t len
)
70 if (buf
->wpos
+ len
> buf
->size
)
71 if (ibuf_realloc(buf
, len
) == -1)
74 memcpy(buf
->buf
+ buf
->wpos
, data
, len
);
79 void *ibuf_reserve(struct ibuf
*buf
, size_t len
)
83 if (buf
->wpos
+ len
> buf
->size
)
84 if (ibuf_realloc(buf
, len
) == -1)
87 b
= buf
->buf
+ buf
->wpos
;
92 void *ibuf_seek(struct ibuf
*buf
, size_t pos
, size_t len
)
94 /* only allowed to seek in already written parts */
95 if (pos
+ len
> buf
->wpos
)
98 return (buf
->buf
+ pos
);
101 size_t ibuf_size(struct ibuf
*buf
)
106 size_t ibuf_left(struct ibuf
*buf
)
108 return (buf
->max
- buf
->wpos
);
111 void ibuf_close(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
113 ibuf_enqueue(msgbuf
, buf
);
116 int ibuf_write(struct msgbuf
*msgbuf
)
118 struct iovec iov
[IOV_MAX
];
123 memset(&iov
, 0, sizeof(iov
));
124 TAILQ_FOREACH (buf
, &msgbuf
->bufs
, entry
) {
127 iov
[i
].iov_base
= buf
->buf
+ buf
->rpos
;
128 iov
[i
].iov_len
= buf
->wpos
- buf
->rpos
;
133 if ((n
= writev(msgbuf
->fd
, iov
, i
)) == -1) {
136 if (errno
== ENOBUFS
)
141 if (n
== 0) { /* connection closed */
146 msgbuf_drain(msgbuf
, n
);
151 void ibuf_free(struct ibuf
*buf
)
159 void msgbuf_init(struct msgbuf
*msgbuf
)
163 TAILQ_INIT(&msgbuf
->bufs
);
166 void msgbuf_drain(struct msgbuf
*msgbuf
, size_t n
)
168 struct ibuf
*buf
, *next
;
170 for (buf
= TAILQ_FIRST(&msgbuf
->bufs
); buf
!= NULL
&& n
> 0;
172 next
= TAILQ_NEXT(buf
, entry
);
173 if (buf
->rpos
+ n
>= buf
->wpos
) {
174 n
-= buf
->wpos
- buf
->rpos
;
176 TAILQ_REMOVE(&msgbuf
->bufs
, buf
, entry
);
177 ibuf_dequeue(msgbuf
, buf
);
185 void msgbuf_clear(struct msgbuf
*msgbuf
)
189 while ((buf
= TAILQ_POP_FIRST(&msgbuf
->bufs
, entry
)) != NULL
)
190 ibuf_dequeue(msgbuf
, buf
);
193 int msgbuf_write(struct msgbuf
*msgbuf
)
195 struct iovec iov
[IOV_MAX
];
200 struct cmsghdr
*cmsg
;
203 char buf
[CMSG_SPACE(sizeof(int))];
206 memset(&iov
, 0, sizeof(iov
));
207 memset(&msg
, 0, sizeof(msg
));
208 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
209 TAILQ_FOREACH (buf
, &msgbuf
->bufs
, entry
) {
212 iov
[i
].iov_base
= buf
->buf
+ buf
->rpos
;
213 iov
[i
].iov_len
= buf
->wpos
- buf
->rpos
;
222 if (buf
!= NULL
&& buf
->fd
!= -1) {
223 msg
.msg_control
= (caddr_t
)&cmsgbuf
.buf
;
224 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
225 cmsg
= CMSG_FIRSTHDR(&msg
);
226 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
227 cmsg
->cmsg_level
= SOL_SOCKET
;
228 cmsg
->cmsg_type
= SCM_RIGHTS
;
229 memcpy(CMSG_DATA(cmsg
), &buf
->fd
, sizeof(int));
233 if ((n
= sendmsg(msgbuf
->fd
, &msg
, 0)) == -1) {
236 if (errno
== ENOBUFS
)
241 if (n
== 0) { /* connection closed */
247 * assumption: fd got sent if sendmsg sent anything
248 * this works because fds are passed one at a time
250 if (buf
!= NULL
&& buf
->fd
!= -1) {
255 msgbuf_drain(msgbuf
, n
);
260 static void ibuf_enqueue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
262 TAILQ_INSERT_TAIL(&msgbuf
->bufs
, buf
, entry
);
266 static void ibuf_dequeue(struct msgbuf
*msgbuf
, struct ibuf
*buf
)
268 /* TAILQ_REMOVE done by caller */