]>
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 if ((n
= recvmsg(ibuf
->fd
, &msg
, 0)) == -1) {
121 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
!= NULL
;
122 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
123 if (cmsg
->cmsg_level
== SOL_SOCKET
124 && cmsg
->cmsg_type
== SCM_RIGHTS
) {
129 * We only accept one file descriptor. Due to C
130 * padding rules, our control buffer might contain
131 * more than one fd, and we must close them.
133 j
= ((char *)cmsg
+ cmsg
->cmsg_len
134 - (char *)CMSG_DATA(cmsg
))
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 */
155 ssize_t
imsg_get(struct imsgbuf
*ibuf
, struct imsg
*imsg
)
157 size_t av
, left
, datalen
;
161 if (IMSG_HEADER_SIZE
> av
)
164 memcpy(&imsg
->hdr
, ibuf
->r
.buf
, sizeof(imsg
->hdr
));
165 if (imsg
->hdr
.len
< IMSG_HEADER_SIZE
|| imsg
->hdr
.len
> MAX_IMSGSIZE
) {
169 if (imsg
->hdr
.len
> av
)
171 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
172 ibuf
->r
.rptr
= ibuf
->r
.buf
+ IMSG_HEADER_SIZE
;
175 else if ((imsg
->data
= malloc(datalen
)) == NULL
)
178 if (imsg
->hdr
.flags
& IMSGF_HASFD
)
179 imsg
->fd
= imsg_get_fd(ibuf
);
184 memcpy(imsg
->data
, ibuf
->r
.rptr
, datalen
);
186 if (imsg
->hdr
.len
< av
) {
187 left
= av
- imsg
->hdr
.len
;
188 memmove(&ibuf
->r
.buf
, ibuf
->r
.buf
+ imsg
->hdr
.len
, left
);
193 return (datalen
+ IMSG_HEADER_SIZE
);
196 int imsg_compose(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
197 pid_t pid
, int fd
, const void *data
, uint16_t datalen
)
201 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
204 if (imsg_add(wbuf
, data
, datalen
) == -1)
209 imsg_close(ibuf
, wbuf
);
214 int imsg_composev(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
215 pid_t pid
, int fd
, const struct iovec
*iov
, int iovcnt
)
220 for (i
= 0; i
< iovcnt
; i
++)
221 datalen
+= iov
[i
].iov_len
;
223 if ((wbuf
= imsg_create(ibuf
, type
, peerid
, pid
, datalen
)) == NULL
)
226 for (i
= 0; i
< iovcnt
; i
++)
227 if (imsg_add(wbuf
, iov
[i
].iov_base
, iov
[i
].iov_len
) == -1)
232 imsg_close(ibuf
, wbuf
);
238 struct ibuf
*imsg_create(struct imsgbuf
*ibuf
, uint32_t type
, uint32_t peerid
,
239 pid_t pid
, uint16_t datalen
)
244 memset(&hdr
, 0x00, IMSG_HEADER_SIZE
);
246 datalen
+= IMSG_HEADER_SIZE
;
247 if (datalen
> MAX_IMSGSIZE
) {
255 if ((hdr
.pid
= pid
) == 0)
257 if ((wbuf
= ibuf_dynamic(datalen
, MAX_IMSGSIZE
)) == NULL
) {
260 if (imsg_add(wbuf
, &hdr
, sizeof(hdr
)) == -1)
266 int imsg_add(struct ibuf
*msg
, const void *data
, uint16_t datalen
)
269 if (ibuf_add(msg
, data
, datalen
) == -1) {
276 void imsg_close(struct imsgbuf
*ibuf
, struct ibuf
*msg
)
278 struct imsg_hdr
*hdr
;
280 hdr
= (struct imsg_hdr
*)msg
->buf
;
282 hdr
->flags
&= ~IMSGF_HASFD
;
284 hdr
->flags
|= IMSGF_HASFD
;
286 hdr
->len
= (uint16_t)msg
->wpos
;
288 ibuf_close(&ibuf
->w
, msg
);
291 void imsg_free(struct imsg
*imsg
)
296 int imsg_get_fd(struct imsgbuf
*ibuf
)
301 if ((ifd
= TAILQ_FIRST(&ibuf
->fds
)) == NULL
)
305 TAILQ_REMOVE(&ibuf
->fds
, ifd
, entry
);
311 int imsg_flush(struct imsgbuf
*ibuf
)
313 while (ibuf
->w
.queued
)
314 if (msgbuf_write(&ibuf
->w
) <= 0)
319 void imsg_clear(struct imsgbuf
*ibuf
)
323 msgbuf_clear(&ibuf
->w
);
324 while ((fd
= imsg_get_fd(ibuf
)) != -1)