xref: /freebsd/share/man/man3/CMSG_DATA.3 (revision 81ad6265)
1.\" Written by Jared Yanovich <jaredy@openbsd.org>
2.\" Public domain, July 3, 2005
3.\"
4.\" $FreeBSD$
5.Dd March 13, 2020
6.Dt CMSG_DATA 3
7.Os
8.Sh NAME
9.Nm CMSG_DATA ,
10.Nm CMSG_FIRSTHDR ,
11.Nm CMSG_LEN ,
12.Nm CMSG_NXTHDR ,
13.Nm CMSG_SPACE
14.Nd socket control message routines for ancillary data access
15.Sh SYNOPSIS
16.In sys/socket.h
17.Ft unsigned char *
18.Fn CMSG_DATA "struct cmsghdr *"
19.Ft struct cmsghdr *
20.Fn CMSG_FIRSTHDR "struct msghdr *"
21.Ft size_t
22.Fn CMSG_LEN "size_t"
23.Ft struct cmsghdr *
24.Fn CMSG_NXTHDR "struct msghdr *" "struct cmsghdr *"
25.Ft size_t
26.Fn CMSG_SPACE "size_t"
27.Sh DESCRIPTION
28The control message API is used to construct ancillary data objects for
29use in control messages sent and received across sockets.
30.Pp
31Control messages are passed around by the
32.Xr recvmsg 2
33and
34.Xr sendmsg 2
35system calls.
36The
37.Vt cmsghdr
38structure, described in
39.Xr recvmsg 2 ,
40is used to specify a chain of control messages.
41.Pp
42These routines should be used instead of directly accessing the control
43message header members and data buffers as they ensure that necessary
44alignment constraints are met.
45.Pp
46The following routines are provided:
47.Bl -tag -width Ds
48.It Fn CMSG_DATA cmsg
49This routine accesses the data portion of the control message header
50.Fa cmsg .
51It ensures proper alignment constraints on the beginning of ancillary
52data are met.
53.It Fn CMSG_FIRSTHDR msghdr
54This routine accesses the first control message attached to the
55message
56.Fa msghdr .
57If no control messages are attached to the message, this routine
58returns
59.Dv NULL .
60.It Fn CMSG_LEN len
61This routine determines the size in bytes of a control message,
62which includes the control message header.
63.Fa len
64specifies the length of the data held by the control message.
65This value is what is normally stored in the
66.Fa cmsg_len
67of each control message.
68This routine accounts for any alignment constraints on the beginning of
69ancillary data.
70.It Fn CMSG_NXTHDR msghdr cmsg
71This routine returns the location of the control message following
72.Fa cmsg
73in the message
74.Fa msghdr .
75If
76.Fa cmsg
77is the last control message in the chain, this routine returns
78.Dv NULL .
79.It Fn CMSG_SPACE len
80This routine determines the size in bytes needed to hold a control
81message and its contents of length
82.Fa len ,
83which includes the control message header.
84This value is what is normally stored in
85.Fa msg_msgcontrollen .
86This routine accounts for any alignment constraints on the beginning of
87ancillary data as well as any needed to pad the next control message.
88.El
89.Sh EXAMPLES
90The following example constructs a control message containing a file descriptor
91in the parent process and passes it over a pre-shared socket over the child
92process.
93Then the child process sends a "hello" string to the parent process using the
94received file descriptor.
95.Bd -literal
96#include <sys/socket.h>
97
98#include <err.h>
99#include <stdio.h>
100#include <string.h>
101#include <sysexits.h>
102#include <unistd.h>
103
104#define	HELLOLEN    sizeof("hello")
105
106int
107main()
108{
109	struct msghdr msg;
110	union {
111		struct cmsghdr hdr;
112		unsigned char	 buf[CMSG_SPACE(sizeof(int))];
113	} cmsgbuf;
114	char buf[HELLOLEN];
115	int hellofd[2];
116	int presharedfd[2];
117	struct cmsghdr *cmsg;
118
119	if (socketpair(PF_LOCAL, SOCK_STREAM, 0, presharedfd) == -1)
120		err(EX_OSERR, "failed to create a pre-shared socket pair");
121
122	memset(&msg, 0, sizeof(msg));
123	msg.msg_control = &cmsgbuf.buf;
124	msg.msg_controllen = sizeof(cmsgbuf.buf);
125	msg.msg_iov = NULL;
126	msg.msg_iovlen = 0;
127
128	switch (fork()) {
129	case -1:
130		err(EX_OSERR, "fork");
131	case 0:
132		close(presharedfd[0]);
133		strlcpy(buf, "hello", HELLOLEN);
134
135		if (recvmsg(presharedfd[1], &msg, 0) == -1)
136			err(EX_IOERR, "failed to receive a message");
137		if (msg.msg_flags & (MSG_CTRUNC | MSG_TRUNC))
138			errx(EX_IOERR, "control message truncated");
139		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
140		    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
141			if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
142			    cmsg->cmsg_level == SOL_SOCKET &&
143			    cmsg->cmsg_type == SCM_RIGHTS) {
144				hellofd[1] = *(int *)CMSG_DATA(cmsg);
145				printf("child: sending '%s'\\n", buf);
146				if (write(hellofd[1], buf, HELLOLEN) == -1)
147				    err(EX_IOERR, "failed to send 'hello'");
148			}
149		}
150		break;
151	default:
152		close(presharedfd[1]);
153
154		if (socketpair(PF_LOCAL, SOCK_STREAM, 0, hellofd) == -1)
155			err(EX_OSERR, "failed to create a 'hello' socket pair");
156
157		cmsg = CMSG_FIRSTHDR(&msg);
158		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
159		cmsg->cmsg_level = SOL_SOCKET;
160		cmsg->cmsg_type = SCM_RIGHTS;
161		*(int *)CMSG_DATA(cmsg) = hellofd[1];
162
163		if (sendmsg(presharedfd[0], &msg, 0) == -1)
164			err(EX_IOERR, "sendmsg");
165		close(hellofd[1]);
166
167		if (read(hellofd[0], buf, HELLOLEN) == -1)
168			err(EX_IOERR, "failed to receive 'hello'");
169		printf("parent: received '%s'\\n", buf);
170		break;
171	}
172
173	return (0);
174}
175.Ed
176.Sh SEE ALSO
177.Xr recvmsg 2 ,
178.Xr sendmsg 2 ,
179.Xr socket 2 ,
180.Xr ip 4 ,
181.Xr ip6 4 ,
182.Xr unix 4
183.Sh STANDARDS
184.Bl -item
185.It
186.Rs
187.%A W. Stevens
188.%A M. Thomas
189.%T "Advanced Sockets API for IPv6"
190.%R RFC 2292
191.%D February 1998
192.Re
193.It
194.Rs
195.%A W. Stevens
196.%A M. Thomas
197.%A E. Nordmark
198.%A T. Jinmei
199.%T "Advanced Sockets Application Program Interface (API) for IPv6"
200.%R RFC 3542
201.%D May 2003
202.Re
203.El
204.Sh HISTORY
205The control message API first appeared in
206.Bx 4.2 .
207This manual page was originally written by
208.An Jared Yanovich Aq Mt jaredy@OpenBSD.org
209for
210.Ox 3.8
211and eventually brought to
212.Fx 12.0
213by
214.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org .
215