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


Reply via email to