1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/posix/unix_domain_socket.h"
10 #include <sys/socket.h>
12 #include "base/logging.h"
13 #include "base/pickle.h"
14 #include "base/posix/eintr_wrapper.h"
15 #include "base/stl_util.h"
17 const size_t UnixDomainSocket::kMaxFileDescriptors
= 16;
20 bool UnixDomainSocket::SendMsg(int fd
,
23 const std::vector
<int>& fds
) {
25 memset(&msg
, 0, sizeof(msg
));
26 struct iovec iov
= {const_cast<void*>(buf
), length
};
30 char* control_buffer
= NULL
;
32 const unsigned control_len
= CMSG_SPACE(sizeof(int) * fds
.size());
33 control_buffer
= new char[control_len
];
36 msg
.msg_control
= control_buffer
;
37 msg
.msg_controllen
= control_len
;
38 cmsg
= CMSG_FIRSTHDR(&msg
);
39 cmsg
->cmsg_level
= SOL_SOCKET
;
40 cmsg
->cmsg_type
= SCM_RIGHTS
;
41 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int) * fds
.size());
42 memcpy(CMSG_DATA(cmsg
), &fds
[0], sizeof(int) * fds
.size());
43 msg
.msg_controllen
= cmsg
->cmsg_len
;
46 // When available, take advantage of MSG_NOSIGNAL to avoid
47 // a SIGPIPE if the other end breaks the connection.
48 #if defined(MSG_NOSIGNAL)
49 const int flags
= MSG_NOSIGNAL
;
53 const ssize_t r
= HANDLE_EINTR(sendmsg(fd
, &msg
, flags
));
54 const bool ret
= static_cast<ssize_t
>(length
) == r
;
55 delete[] control_buffer
;
60 ssize_t
UnixDomainSocket::RecvMsg(int fd
,
63 std::vector
<int>* fds
) {
67 memset(&msg
, 0, sizeof(msg
));
68 struct iovec iov
= {buf
, length
};
72 char control_buffer
[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors
)];
73 msg
.msg_control
= control_buffer
;
74 msg
.msg_controllen
= sizeof(control_buffer
);
76 const ssize_t r
= HANDLE_EINTR(recvmsg(fd
, &msg
, 0));
81 unsigned wire_fds_len
= 0;
83 if (msg
.msg_controllen
> 0) {
85 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
86 if (cmsg
->cmsg_level
== SOL_SOCKET
&&
87 cmsg
->cmsg_type
== SCM_RIGHTS
) {
88 const unsigned payload_len
= cmsg
->cmsg_len
- CMSG_LEN(0);
89 DCHECK(payload_len
% sizeof(int) == 0);
90 wire_fds
= reinterpret_cast<int*>(CMSG_DATA(cmsg
));
91 wire_fds_len
= payload_len
/ sizeof(int);
97 if (msg
.msg_flags
& MSG_TRUNC
|| msg
.msg_flags
& MSG_CTRUNC
) {
98 for (unsigned i
= 0; i
< wire_fds_len
; ++i
)
104 fds
->resize(wire_fds_len
);
105 memcpy(vector_as_array(fds
), wire_fds
, sizeof(int) * wire_fds_len
);
111 ssize_t
UnixDomainSocket::SendRecvMsg(int fd
,
113 unsigned max_reply_len
,
115 const Pickle
& request
) {
118 // This socketpair is only used for the IPC and is cleaned up before
120 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, fds
) == -1)
123 std::vector
<int> fd_vector
;
124 fd_vector
.push_back(fds
[1]);
125 if (!SendMsg(fd
, request
.data(), request
.size(), fd_vector
)) {
133 const ssize_t reply_len
= RecvMsg(fds
[0], reply
, max_reply_len
, &fd_vector
);
138 if ((!fd_vector
.empty() && result_fd
== NULL
) || fd_vector
.size() > 1) {
139 for (std::vector
<int>::const_iterator
140 i
= fd_vector
.begin(); i
!= fd_vector
.end(); ++i
) {
150 *result_fd
= fd_vector
.empty() ? -1 : fd_vector
[0];