]>
git.proxmox.com Git - mirror_frr.git/blob - lib/imsg.c
1 // SPDX-License-Identifier: ISC
5 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
14 static int imsg_fd_overhead
= 0;
16 static int imsg_get_fd(struct imsgbuf
*);
20 * The original code calls getdtablecount() which is OpenBSD specific. Use
21 * available_fds() from OpenSMTPD instead.
23 static int available_fds(unsigned int n
)
28 if (n
> (unsigned int)array_size(fds
))
32 for (i
= 0; i
< n
; i
++) {
34 if ((fds
[i
] = socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
35 if (errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
)
36 fds
[i
] = socket(AF_INET6
, SOCK_DGRAM
, 0);
44 for (i
= 0; i
< n
&& fds
[i
] >= 0; i
++)
51 void imsg_init(struct imsgbuf
*ibuf
, int fd
)
53 msgbuf_init(&ibuf
->w
);
54 memset(&ibuf
->r
, 0, sizeof(ibuf
->r
));
58 TAILQ_INIT(&ibuf
->fds
);
61 ssize_t
imsg_read(struct imsgbuf
*ibuf
)
67 char buf
[CMSG_SPACE(sizeof(int) * 1)];
74 memset(&msg
, 0, sizeof(msg
));
75 memset(&cmsgbuf
, 0, sizeof(cmsgbuf
));
77 iov
.iov_base
= ibuf
->r
.buf
+ ibuf
->r
.wpos
;
78 iov
.iov_len
= sizeof(ibuf
->r
.buf
) - ibuf
->r
.wpos
;
81 msg
.msg_control
= &cmsgbuf
.buf
;
82 msg
.msg_controllen
= sizeof(cmsgbuf
.buf
);
84 if ((ifd
= calloc(1, sizeof(struct imsg_fd
))) == NULL
)
89 if (getdtablecount() + imsg_fd_overhead
90 + (int)((CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
94 if (available_fds(imsg_fd_overhead
95 + (CMSG_SPACE(sizeof(int)) - CMSG_SPACE(0))
103 n
= recvmsg(ibuf
->fd
, &msg
, 0);
112 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
!= NULL
;
113 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
114 if (cmsg
->cmsg_level
== SOL_SOCKET
115 && cmsg
->cmsg_type
== SCM_RIGHTS
) {
120 * We only accept one file descriptor. Due to C
121 * padding rules, our control buffer might contain
122 * more than one fd, and we must close them.
124 j
= ((char *)cmsg
+ cmsg
->cmsg_len
125 - (char *)CMSG_DATA(cmsg
))
127 for (i
= 0; i
< j
; i
++) {
128 fd
= ((int *)CMSG_DATA(cmsg
))[i
];
131 TAILQ_INSERT_TAIL(&ibuf
->fds
, ifd
,
138 /* we do not handle other ctl data level */
146 ssize_t
imsg_get(struct imsgbuf
*ibuf
, struct imsg
*imsg
)
148 size_t av
, left
, datalen
;
152 if (IMSG_HEADER_SIZE
> av
)
155 memcpy(&imsg
->hdr
, ibuf
->r
.buf
, sizeof(imsg
->hdr
));
156 if (imsg
->hdr
.len
< IMSG_HEADER_SIZE
|| imsg
->hdr
.len
> MAX_IMSGSIZE
) {
160 if (imsg
->hdr
.len
> av
)
162 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
163 ibuf
->r
.rptr
= ibuf
->r
.buf
+ IMSG_HEADER_SIZE
;
166 else if ((imsg
->data
= malloc(datalen
)) == NULL
)
169 if (imsg
->hdr
.flags
& IMSGF_HASFD
)
170 imsg
->fd
= imsg_get_fd(ibuf
);
175 memcpy(imsg
->data
, ibuf
->r
.rptr
, datalen
);
177 if (imsg
->hdr
.len
< av
) {
178 left
= av
- imsg
->hdr
.len
;
179 memmove(&ibuf
->r
.buf
, ibuf
->r
.buf
+ imsg
->hdr
.len
, left
);
184 return (datalen
+ IMSG_HEADER_SIZE
);
187 int imsg_compose(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
188 pid_t pid
, int fd
, const void *data
, uint16_t datalen
)
192 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
195 if (imsg_add(wbuf
, data
, datalen
) == -1)
200 imsg_close(ibuf
, wbuf
);
205 int imsg_composev(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
206 pid_t pid
, int fd
, const struct iovec
*iov
, int iovcnt
)
211 for (i
= 0; i
< iovcnt
; i
++)
212 datalen
+= iov
[i
].iov_len
;
214 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
217 for (i
= 0; i
< iovcnt
; i
++)
218 if (imsg_add(wbuf
, iov
[i
].iov_base
, iov
[i
].iov_len
) == -1)
223 imsg_close(ibuf
, wbuf
);
229 struct ibuf
*imsg_create(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
230 pid_t pid
, uint16_t datalen
)
235 memset(&hdr
, 0x00, IMSG_HEADER_SIZE
);
237 datalen
+= IMSG_HEADER_SIZE
;
238 if (datalen
> MAX_IMSGSIZE
) {
246 if ((hdr
.pid
= pid
) == 0)
248 if ((wbuf
= ibuf_dynamic(datalen
, MAX_IMSGSIZE
)) == NULL
) {
251 if (imsg_add(wbuf
, &hdr
, sizeof(hdr
)) == -1)
257 int imsg_add(struct ibuf
*msg
, const void *data
, uint16_t datalen
)
260 if (ibuf_add(msg
, data
, datalen
) == -1) {
267 void imsg_close(struct imsgbuf
*ibuf
, struct ibuf
*msg
)
269 struct imsg_hdr
*hdr
;
271 hdr
= (struct imsg_hdr
*)msg
->buf
;
273 hdr
->flags
&= ~IMSGF_HASFD
;
275 hdr
->flags
|= IMSGF_HASFD
;
277 hdr
->len
= (uint16_t)msg
->wpos
;
279 ibuf_close(&ibuf
->w
, msg
);
282 void imsg_free(struct imsg
*imsg
)
287 int imsg_get_fd(struct imsgbuf
*ibuf
)
292 if ((ifd
= TAILQ_POP_FIRST(&ibuf
->fds
, entry
)) == NULL
)
301 int imsg_flush(struct imsgbuf
*ibuf
)
303 while (ibuf
->w
.queued
)
304 if (msgbuf_write(&ibuf
->w
) <= 0)
309 void imsg_clear(struct imsgbuf
*ibuf
)
313 msgbuf_clear(&ibuf
->w
);
314 while ((fd
= imsg_get_fd(ibuf
)) != -1)