]>
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.
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.
33 static int available_fds(unsigned int n
)
38 if (n
> (sizeof(fds
) / sizeof(fds
[0])))
42 for (i
= 0; i
< n
; i
++) {
44 if ((fds
[i
] = socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
45 if (errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
)
46 fds
[i
] = socket(AF_INET6
, SOCK_DGRAM
, 0);
54 for (i
= 0; i
< n
&& fds
[i
] >= 0; i
++)
61 void imsg_init(struct imsgbuf
*ibuf
, int fd
)
63 msgbuf_init(&ibuf
->w
);
64 memset(&ibuf
->r
, 0, sizeof(ibuf
->r
));
68 TAILQ_INIT(&ibuf
->fds
);
71 ssize_t
imsg_read(struct imsgbuf
*ibuf
)
77 char buf
[CMSG_SPACE(sizeof(int) * 1)];
84 memset(&msg
, 0, sizeof(msg
));
85 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
87 iov
.iov_base
= ibuf
->r
.buf
+ ibuf
->r
.wpos
;
88 iov
.iov_len
= sizeof(ibuf
->r
.buf
) - ibuf
->r
.wpos
;
91 msg
.msg_control
= &cmsgbuf
.buf
;
92 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
94 if ((ifd
= calloc(1, sizeof(struct imsg_fd
))) == NULL
)
99 if (getdtablecount() + imsg_fd_overhead
100 + (int)((CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
102 >= getdtablesize()) {
104 if (available_fds(imsg_fd_overhead
105 + (CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
113 n
= recvmsg(ibuf
->fd
, &msg
, 0);
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
))
137 for (i
= 0; i
< j
; i
++) {
138 fd
= ((int *)CMSG_DATA(cmsg
))[i
];
141 TAILQ_INSERT_TAIL(&ibuf
->fds
, ifd
,
148 /* we do not handle other ctl data level */
156 ssize_t
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
|| imsg
->hdr
.len
> MAX_IMSGSIZE
) {
170 if (imsg
->hdr
.len
> av
)
172 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
173 ibuf
->r
.rptr
= ibuf
->r
.buf
+ IMSG_HEADER_SIZE
;
176 else if ((imsg
->data
= malloc(datalen
)) == NULL
)
179 if (imsg
->hdr
.flags
& IMSGF_HASFD
)
180 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
);
197 int imsg_compose(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
198 pid_t pid
, int fd
, const void *data
, uint16_t datalen
)
202 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
205 if (imsg_add(wbuf
, data
, datalen
) == -1)
210 imsg_close(ibuf
, wbuf
);
215 int imsg_composev(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
216 pid_t pid
, int fd
, const struct iovec
*iov
, int iovcnt
)
221 for (i
= 0; i
< iovcnt
; i
++)
222 datalen
+= iov
[i
].iov_len
;
224 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
227 for (i
= 0; i
< iovcnt
; i
++)
228 if (imsg_add(wbuf
, iov
[i
].iov_base
, iov
[i
].iov_len
) == -1)
233 imsg_close(ibuf
, wbuf
);
239 struct ibuf
*imsg_create(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
240 pid_t pid
, uint16_t datalen
)
245 memset(&hdr
, 0x00, IMSG_HEADER_SIZE
);
247 datalen
+= IMSG_HEADER_SIZE
;
248 if (datalen
> MAX_IMSGSIZE
) {
256 if ((hdr
.pid
= pid
) == 0)
258 if ((wbuf
= ibuf_dynamic(datalen
, MAX_IMSGSIZE
)) == NULL
) {
261 if (imsg_add(wbuf
, &hdr
, sizeof(hdr
)) == -1)
267 int imsg_add(struct ibuf
*msg
, const void *data
, uint16_t datalen
)
270 if (ibuf_add(msg
, data
, datalen
) == -1) {
277 void imsg_close(struct imsgbuf
*ibuf
, struct ibuf
*msg
)
279 struct imsg_hdr
*hdr
;
281 hdr
= (struct imsg_hdr
*)msg
->buf
;
283 hdr
->flags
&= ~IMSGF_HASFD
;
285 hdr
->flags
|= IMSGF_HASFD
;
287 hdr
->len
= (uint16_t)msg
->wpos
;
289 ibuf_close(&ibuf
->w
, msg
);
292 void imsg_free(struct imsg
*imsg
)
297 int imsg_get_fd(struct imsgbuf
*ibuf
)
302 if ((ifd
= TAILQ_FIRST(&ibuf
->fds
)) == NULL
)
306 TAILQ_REMOVE(&ibuf
->fds
, ifd
, entry
);
312 int imsg_flush(struct imsgbuf
*ibuf
)
314 while (ibuf
->w
.queued
)
315 if (msgbuf_write(&ibuf
->w
) <= 0)
320 void imsg_clear(struct imsgbuf
*ibuf
)
324 msgbuf_clear(&ibuf
->w
);
325 while ((fd
= imsg_get_fd(ibuf
)) != -1)