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