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_linux.h"
8 #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) {
24 struct msghdr msg = {};
25 struct iovec iov = { const_cast<void*>(buf), length };
29 char* control_buffer = NULL;
31 const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
32 control_buffer = new char[control_len];
35 msg.msg_control = control_buffer;
36 msg.msg_controllen = control_len;
37 cmsg = CMSG_FIRSTHDR(&msg);
38 cmsg->cmsg_level = SOL_SOCKET;
39 cmsg->cmsg_type = SCM_RIGHTS;
40 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
41 memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
42 msg.msg_controllen = cmsg->cmsg_len;
45 // Avoid a SIGPIPE if the other end breaks the connection.
46 // Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't
47 // regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by
49 const int flags = MSG_NOSIGNAL;
50 const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, flags));
51 const bool ret = static_cast<ssize_t>(length) == r;
52 delete[] control_buffer;
57 ssize_t UnixDomainSocket::RecvMsg(int fd,
60 std::vector<int>* fds) {
61 return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds);
65 ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
69 std::vector<int>* fds) {
72 struct msghdr msg = {};
73 struct iovec iov = { buf, length };
77 char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)];
78 msg.msg_control = control_buffer;
79 msg.msg_controllen = sizeof(control_buffer);
81 const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags));
86 unsigned wire_fds_len = 0;
88 if (msg.msg_controllen > 0) {
90 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
91 if (cmsg->cmsg_level == SOL_SOCKET &&
92 cmsg->cmsg_type == SCM_RIGHTS) {
93 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
94 DCHECK(payload_len % sizeof(int) == 0);
95 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
96 wire_fds_len = payload_len / sizeof(int);
102 if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
103 for (unsigned i = 0; i < wire_fds_len; ++i)
109 fds->resize(wire_fds_len);
110 memcpy(vector_as_array(fds), wire_fds, sizeof(int) * wire_fds_len);
116 ssize_t UnixDomainSocket::SendRecvMsg(int fd,
118 unsigned max_reply_len,
120 const Pickle& request) {
121 return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len,
122 0, /* recvmsg_flags */
127 ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
129 unsigned max_reply_len,
132 const Pickle& request) {
135 // This socketpair is only used for the IPC and is cleaned up before
137 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == -1)
140 std::vector<int> fd_vector;
141 fd_vector.push_back(fds[1]);
142 if (!SendMsg(fd, request.data(), request.size(), fd_vector)) {
150 // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
151 // sender might get a SIGPIPE.
152 const ssize_t reply_len = RecvMsgWithFlags(fds[0], reply, max_reply_len,
153 recvmsg_flags, &fd_vector);
158 if ((!fd_vector.empty() && result_fd == NULL) || fd_vector.size() > 1) {
159 for (std::vector<int>::const_iterator
160 i = fd_vector.begin(); i != fd_vector.end(); ++i) {
170 *result_fd = fd_vector.empty() ? -1 : fd_vector[0];