1 /* Copyright (C) 2011-2025 Free Software Foundation, Inc.
3 This file is free software: you can redistribute it and/or modify
4 it under the terms of the GNU Lesser General Public License as
5 published by the Free Software Foundation; either version 2.1 of the
6 License, or (at your option) any later version.
8 This file 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 Lesser General Public License for more details.
13 You should have received a copy of the GNU Lesser 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
)
55 # if defined CMSG_FIRSTHDR && !defined __sgi
57 char buf
[CMSG_SPACE (sizeof fd
)];
60 /* send at least one char */
61 memset (&msg
, 0, sizeof msg
);
69 # if defined CMSG_FIRSTHDR && !defined __sgi
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 (_GL_UNUSED
int sock
, _GL_UNUSED
int fd
)
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 # if defined CMSG_FIRSTHDR && !defined __sgi
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 # if defined CMSG_FIRSTHDR && !defined __sgi
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_SPACE (sizeof fd
);
147 len
= recvmsg (sock
, &msg
, flags_recvmsg
);
152 /* fake errno: at end the file is not available */
156 cmsg
= CMSG_FIRSTHDR (&msg
);
158 if (cmsg
== NULL
|| cmsg
->cmsg_len
!= CMSG_LEN (sizeof fd
)
159 || cmsg
->cmsg_level
!= SOL_SOCKET
|| cmsg
->cmsg_type
!= SCM_RIGHTS
)
165 memcpy (&fd
, CMSG_DATA (cmsg
), sizeof fd
);
167 /* set close-on-exec flag */
168 if (!MSG_CMSG_CLOEXEC
&& (flags
& O_CLOEXEC
))
170 if (set_cloexec_flag (fd
, true) < 0)
172 int saved_errno
= errno
;
179 # elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
180 msg
.msg_accrights
= &fd
;
181 msg
.msg_accrightslen
= sizeof fd
;
182 if (recvmsg (sock
, &msg
, 0) < 0)
185 /* set close-on-exec flag */
186 if (flags
& O_CLOEXEC
)
188 if (set_cloexec_flag (fd
, true) < 0)
190 int saved_errno
= errno
;
197 if (fd
< 0 && errno
== 0)
207 recvfd (_GL_UNUSED
int sock
, _GL_UNUSED
int flags
)