i couldnt find any good examples of what to do when you wanted to receive multiple control messages from a single recvmsg call. the most interesting bit is how much space the buffer needs to be.
if i struggled maybe someone else will too? Index: CMSG_DATA.3 =================================================================== RCS file: /cvs/src/share/man/man3/CMSG_DATA.3,v retrieving revision 1.6 diff -u -p -r1.6 CMSG_DATA.3 --- CMSG_DATA.3 3 Apr 2017 19:40:43 -0000 1.6 +++ CMSG_DATA.3 22 Mar 2022 04:23:50 -0000 @@ -116,7 +116,8 @@ if (sendmsg(s, &msg, 0) == -1) err(1, "sendmsg"); .Ed .Pp -And an example that receives and decomposes the control message: +The following example receives and decomposes a control message +containing a file descriptor: .Bd -literal -offset indent struct msghdr msg; struct cmsghdr *cmsg; @@ -146,6 +147,62 @@ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != cmsg->cmsg_type == SCM_RIGHTS) { fd = *(int *)CMSG_DATA(cmsg); /* Do something with the descriptor. */ + } +} +.Ed +.Pp +The following example shows how to to receive multiple control +messages for a single datagram. +In this example a program is receiving an IPv4 UDP datagram +using a socket that has been configured to provide the local +(destination) IP address and port using +.Xr setsockopt 2 +and the +.Dv IP_RECVDSTADDR +and +.Dv IP_RECVDSTADDR +.Xr ip 4 +options respectively. +.Bd -literal -offset indent +struct msghdr msg; +struct cmsghdr *cmsg; +union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(struct in_addr)) + + CMSG_SPACE(sizeof(in_port_t))]; +} cmsgbuf; +struct sockaddr_in sin; +struct iovec io_vector[1]; + +sin.sin_family = AF_INET; + +io_vector[0].iov_base = &ch; +io_vector[0].iov_len = 1; + +memset(&msg, 0, sizeof(msg)); +msg.msg_control = &cmsgbuf.buf; +msg.msg_controllen = sizeof(cmsgbuf.buf); +msg.msg_iov = io_vector; +msg.msg_iovlen = 1; + +if (recvmsg(s, &msg, 0) == -1) + err(1, "recvmsg"); +if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) + errx(1, "control message truncated"); +for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_len == CMSG_LEN(sizeof(struct sockaddr_in)) && + cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVDSTADDR) { + sin.sin_addr = *(struct in_addr *)CMSG_DATA(cmsg); + continue; + } + + if (cmsg->cmsg_len == CMSG_LEN(sizeof(in_port_t)) && + cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVDSTPORT) { + sin.sin_port = *(in_port_t *)CMSG_DATA(cmsg); + continue; } } .Ed