1 /* Copyright (C) 2011-2020 Free Software Foundation, Inc.
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 3 of the License, or
6 (at your option) any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>. */
26 #include <sys/types.h>
29 #include <sys/socket.h>
33 /* The code that uses CMSG_FIRSTHDR is enabled on
34 Linux, Mac OS X, FreeBSD, OpenBSD, NetBSD, AIX, OSF/1, Cygwin.
35 The code that uses HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS is enabled on
36 HP-UX, IRIX, Solaris. */
38 /* MSG_CMSG_CLOEXEC is defined only on Linux, as of 2011. */
39 #ifndef MSG_CMSG_CLOEXEC
40 # define MSG_CMSG_CLOEXEC 0
44 /* sendfd sends the file descriptor fd along the socket
45 to a process calling recvfd on the other end.
47 Return 0 on success, or -1 with errno set in case of error.
50 sendfd (int sock
, int fd
)
57 char buf
[CMSG_SPACE (sizeof fd
)];
60 /* send at least one char */
61 memset (&msg
, 0, sizeof msg
);
70 msg
.msg_control
= buf
;
71 msg
.msg_controllen
= sizeof buf
;
72 cmsg
= CMSG_FIRSTHDR (&msg
);
73 cmsg
->cmsg_level
= SOL_SOCKET
;
74 cmsg
->cmsg_type
= SCM_RIGHTS
;
75 cmsg
->cmsg_len
= CMSG_LEN (sizeof fd
);
76 /* Initialize the payload: */
77 memcpy (CMSG_DATA (cmsg
), &fd
, sizeof fd
);
78 msg
.msg_controllen
= cmsg
->cmsg_len
;
79 # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
80 msg
.msg_accrights
= &fd
;
81 msg
.msg_accrightslen
= sizeof fd
;
87 if (sendmsg (sock
, &msg
, 0) != iov
.iov_len
)
93 sendfd (int sock _GL_UNUSED
, int fd _GL_UNUSED
)
102 /* recvfd receives a file descriptor through the socket.
103 The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).
105 Return the fd on success, or -1 with errno set in case of error.
108 recvfd (int sock
, int flags
)
115 # ifdef CMSG_FIRSTHDR
116 struct cmsghdr
*cmsg
;
117 char buf
[CMSG_SPACE (sizeof fd
)];
118 int flags_recvmsg
= flags
& O_CLOEXEC
? MSG_CMSG_CLOEXEC
: 0;
121 if ((flags
& ~O_CLOEXEC
) != 0)
127 /* send at least one char */
128 memset (&msg
, 0, sizeof msg
);
129 iov
.iov_base
= &byte
;
136 # ifdef CMSG_FIRSTHDR
137 msg
.msg_control
= buf
;
138 msg
.msg_controllen
= sizeof buf
;
139 cmsg
= CMSG_FIRSTHDR (&msg
);
140 cmsg
->cmsg_level
= SOL_SOCKET
;
141 cmsg
->cmsg_type
= SCM_RIGHTS
;
142 cmsg
->cmsg_len
= CMSG_LEN (sizeof fd
);
143 /* Initialize the payload: */
144 memcpy (CMSG_DATA (cmsg
), &fd
, sizeof fd
);
145 msg
.msg_controllen
= cmsg
->cmsg_len
;
147 len
= recvmsg (sock
, &msg
, flags_recvmsg
);
151 cmsg
= CMSG_FIRSTHDR (&msg
);
153 if (len
== 0 || cmsg
== NULL
|| cmsg
->cmsg_len
!= CMSG_LEN (sizeof fd
)
154 || cmsg
->cmsg_level
!= SOL_SOCKET
|| cmsg
->cmsg_type
!= SCM_RIGHTS
)
156 /* fake errno: at end the file is not available */
157 errno
= len
? EACCES
: ENOTCONN
;
161 memcpy (&fd
, CMSG_DATA (cmsg
), sizeof fd
);
163 /* set close-on-exec flag */
164 if (!MSG_CMSG_CLOEXEC
&& (flags
& O_CLOEXEC
))
166 if (set_cloexec_flag (fd
, true) < 0)
168 int saved_errno
= errno
;
175 # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
176 msg
.msg_accrights
= &fd
;
177 msg
.msg_accrightslen
= sizeof fd
;
178 if (recvmsg (sock
, &msg
, 0) < 0)
181 /* set close-on-exec flag */
182 if (flags
& O_CLOEXEC
)
184 if (set_cloexec_flag (fd
, true) < 0)
186 int saved_errno
= errno
;
200 recvfd (int sock _GL_UNUSED
, int flags _GL_UNUSED
)