]>
git.proxmox.com Git - mirror_frr.git/blob - lib/imsg.c
4 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
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
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 #include "openbsd-queue.h"
24 int imsg_fd_overhead
= 0;
26 int imsg_get_fd(struct imsgbuf
*);
30 * The original code calls getdtablecount() which is OpenBSD specific. Use
31 * available_fds() from OpenSMTPD instead.
34 available_fds(unsigned int n
)
39 if (n
> (sizeof(fds
)/sizeof(fds
[0])))
43 for (i
= 0; i
< n
; i
++) {
45 if ((fds
[i
] = socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
46 if (errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
)
47 fds
[i
] = socket(AF_INET6
, SOCK_DGRAM
, 0);
55 for (i
= 0; i
< n
&& fds
[i
] >= 0; i
++)
63 imsg_init(struct imsgbuf
*ibuf
, int fd
)
65 msgbuf_init(&ibuf
->w
);
66 memset(&ibuf
->r
, 0, sizeof(ibuf
->r
));
70 TAILQ_INIT(&ibuf
->fds
);
74 imsg_read(struct imsgbuf
*ibuf
)
80 char buf
[CMSG_SPACE(sizeof(int) * 1)];
87 memset(&msg
, 0, sizeof(msg
));
88 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
90 iov
.iov_base
= ibuf
->r
.buf
+ ibuf
->r
.wpos
;
91 iov
.iov_len
= sizeof(ibuf
->r
.buf
) - ibuf
->r
.wpos
;
94 msg
.msg_control
= &cmsgbuf
.buf
;
95 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
97 if ((ifd
= calloc(1, sizeof(struct imsg_fd
))) == NULL
)
102 if (getdtablecount() + imsg_fd_overhead
+
103 (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
104 >= getdtablesize()) {
106 if (available_fds(imsg_fd_overhead
+
107 (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) {
114 if ((n
= recvmsg(ibuf
->fd
, &msg
, 0)) == -1) {
122 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
!= NULL
;
123 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
124 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
125 cmsg
->cmsg_type
== SCM_RIGHTS
) {
130 * We only accept one file descriptor. Due to C
131 * padding rules, our control buffer might contain
132 * more than one fd, and we must close them.
134 j
= ((char *)cmsg
+ cmsg
->cmsg_len
-
135 (char *)CMSG_DATA(cmsg
)) / sizeof(int);
136 for (i
= 0; i
< j
; i
++) {
137 fd
= ((int *)CMSG_DATA(cmsg
))[i
];
140 TAILQ_INSERT_TAIL(&ibuf
->fds
, ifd
,
147 /* we do not handle other ctl data level */
156 imsg_get(struct imsgbuf
*ibuf
, struct imsg
*imsg
)
158 size_t av
, left
, datalen
;
162 if (IMSG_HEADER_SIZE
> av
)
165 memcpy(&imsg
->hdr
, ibuf
->r
.buf
, sizeof(imsg
->hdr
));
166 if (imsg
->hdr
.len
< IMSG_HEADER_SIZE
||
167 imsg
->hdr
.len
> MAX_IMSGSIZE
) {
171 if (imsg
->hdr
.len
> av
)
173 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
174 ibuf
->r
.rptr
= ibuf
->r
.buf
+ IMSG_HEADER_SIZE
;
177 else if ((imsg
->data
= malloc(datalen
)) == NULL
)
180 if (imsg
->hdr
.flags
& IMSGF_HASFD
)
181 imsg
->fd
= imsg_get_fd(ibuf
);
185 memcpy(imsg
->data
, ibuf
->r
.rptr
, datalen
);
187 if (imsg
->hdr
.len
< av
) {
188 left
= av
- imsg
->hdr
.len
;
189 memmove(&ibuf
->r
.buf
, ibuf
->r
.buf
+ imsg
->hdr
.len
, left
);
194 return (datalen
+ IMSG_HEADER_SIZE
);
198 imsg_compose(struct imsgbuf
*ibuf
, u_int32_t type
, u_int32_t peerid
,
199 pid_t pid
, int fd
, const void *data
, u_int16_t datalen
)
203 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
206 if (imsg_add(wbuf
, data
, datalen
) == -1)
211 imsg_close(ibuf
, wbuf
);
217 imsg_composev(struct imsgbuf
*ibuf
, u_int32_t type
, u_int32_t peerid
,
218 pid_t pid
, int fd
, const struct iovec
*iov
, int iovcnt
)
223 for (i
= 0; i
< iovcnt
; i
++)
224 datalen
+= iov
[i
].iov_len
;
226 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
229 for (i
= 0; i
< iovcnt
; i
++)
230 if (imsg_add(wbuf
, iov
[i
].iov_base
, iov
[i
].iov_len
) == -1)
235 imsg_close(ibuf
, wbuf
);
242 imsg_create(struct imsgbuf
*ibuf
, u_int32_t type
, u_int32_t peerid
,
243 pid_t pid
, u_int16_t datalen
)
248 datalen
+= IMSG_HEADER_SIZE
;
249 if (datalen
> MAX_IMSGSIZE
) {
257 if ((hdr
.pid
= pid
) == 0)
259 if ((wbuf
= ibuf_dynamic(datalen
, MAX_IMSGSIZE
)) == NULL
) {
262 if (imsg_add(wbuf
, &hdr
, sizeof(hdr
)) == -1)
269 imsg_add(struct ibuf
*msg
, const void *data
, u_int16_t datalen
)
272 if (ibuf_add(msg
, data
, datalen
) == -1) {
280 imsg_close(struct imsgbuf
*ibuf
, struct ibuf
*msg
)
282 struct imsg_hdr
*hdr
;
284 hdr
= (struct imsg_hdr
*)msg
->buf
;
286 hdr
->flags
&= ~IMSGF_HASFD
;
288 hdr
->flags
|= IMSGF_HASFD
;
290 hdr
->len
= (u_int16_t
)msg
->wpos
;
292 ibuf_close(&ibuf
->w
, msg
);
296 imsg_free(struct imsg
*imsg
)
302 imsg_get_fd(struct imsgbuf
*ibuf
)
307 if ((ifd
= TAILQ_FIRST(&ibuf
->fds
)) == NULL
)
311 TAILQ_REMOVE(&ibuf
->fds
, ifd
, entry
);
318 imsg_flush(struct imsgbuf
*ibuf
)
320 while (ibuf
->w
.queued
)
321 if (msgbuf_write(&ibuf
->w
) <= 0)
327 imsg_clear(struct imsgbuf
*ibuf
)
331 msgbuf_clear(&ibuf
->w
);
332 while ((fd
= imsg_get_fd(ibuf
)) != -1)