15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/unix_domain_socket_linux.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <sys/uio.h>
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <unistd.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <vector>
135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/files/scoped_file.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/memory/scoped_vector.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/pickle.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Creates a connected pair of UNIX-domain SOCK_SEQPACKET sockets, and passes
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// ownership of the newly allocated file descriptors to |one| and |two|.
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Returns true on success.
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liustatic bool CreateSocketPair(base::ScopedFD* one, base::ScopedFD* two) {
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int raw_socks[2];
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks) == -1)
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return false;
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  one->reset(raw_socks[0]);
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  two->reset(raw_socks[1]);
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return true;
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubool UnixDomainSocket::EnableReceiveProcessId(int fd) {
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const int enable = 1;
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)) == 0;
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool UnixDomainSocket::SendMsg(int fd,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const void* buf,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               size_t length,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const std::vector<int>& fds) {
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct msghdr msg = {};
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct iovec iov = { const_cast<void*>(buf), length };
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg.msg_iov = &iov;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg.msg_iovlen = 1;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char* control_buffer = NULL;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (fds.size()) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    control_buffer = new char[control_len];
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    struct cmsghdr* cmsg;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.msg_control = control_buffer;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.msg_controllen = control_len;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmsg = CMSG_FIRSTHDR(&msg);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmsg->cmsg_level = SOL_SOCKET;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmsg->cmsg_type = SCM_RIGHTS;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    msg.msg_controllen = cmsg->cmsg_len;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Avoid a SIGPIPE if the other end breaks the connection.
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // POSIX.
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const int flags = MSG_NOSIGNAL;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, flags));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const bool ret = static_cast<ssize_t>(length) == r;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete[] control_buffer;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ssize_t UnixDomainSocket::RecvMsg(int fd,
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  void* buf,
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  size_t length,
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                  ScopedVector<base::ScopedFD>* fds) {
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liussize_t UnixDomainSocket::RecvMsgWithPid(int fd,
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                         void* buf,
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                         size_t length,
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                         ScopedVector<base::ScopedFD>* fds,
915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                         base::ProcessId* pid) {
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           void* buf,
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           size_t length,
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                           int flags,
1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                           ScopedVector<base::ScopedFD>* fds,
1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                           base::ProcessId* out_pid) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fds->clear();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct msghdr msg = {};
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  struct iovec iov = { buf, length };
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg.msg_iov = &iov;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg.msg_iovlen = 1;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors) +
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                      CMSG_SPACE(sizeof(struct ucred))];
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg.msg_control = control_buffer;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  msg.msg_controllen = sizeof(control_buffer);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags));
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (r == -1)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int* wire_fds = NULL;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned wire_fds_len = 0;
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::ProcessId pid = -1;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (msg.msg_controllen > 0) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct cmsghdr* cmsg;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (cmsg->cmsg_level == SOL_SOCKET &&
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          cmsg->cmsg_type == SCM_RIGHTS) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DCHECK(payload_len % sizeof(int) == 0);
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        DCHECK(wire_fds == NULL);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        wire_fds_len = payload_len / sizeof(int);
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      }
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if (cmsg->cmsg_level == SOL_SOCKET &&
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          cmsg->cmsg_type == SCM_CREDENTIALS) {
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        DCHECK(payload_len == sizeof(struct ucred));
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        DCHECK(pid == -1);
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (unsigned i = 0; i < wire_fds_len; ++i)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close(wire_fds[i]);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errno = EMSGSIZE;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (wire_fds) {
1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    for (unsigned i = 0; i < wire_fds_len; ++i)
1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      fds->push_back(new base::ScopedFD(wire_fds[i]));
1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (out_pid) {
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // |pid| will legitimately be -1 if we read EOF, so only DCHECK if we
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // actually received a message.  Unfortunately, Linux allows sending zero
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // length messages, which are indistinguishable from EOF, so this check
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // has false negatives.
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (r > 0 || msg.msg_controllen > 0)
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      DCHECK_GE(pid, 0);
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    *out_pid = pid;
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return r;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ssize_t UnixDomainSocket::SendRecvMsg(int fd,
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      uint8_t* reply,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      unsigned max_reply_len,
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      int* result_fd,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const Pickle& request) {
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len,
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                0,  /* recvmsg_flags */
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                result_fd, request);
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
178c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
179c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               uint8_t* reply,
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               unsigned max_reply_len,
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               int recvmsg_flags,
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               int* result_fd,
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                               const Pickle& request) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This socketpair is only used for the IPC and is cleaned up before
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // returning.
1885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::ScopedFD recv_sock, send_sock;
1895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!CreateSocketPair(&recv_sock, &send_sock))
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  {
1935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    std::vector<int> send_fds;
1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    send_fds.push_back(send_sock.get());
1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (!SendMsg(fd, request.data(), request.size(), send_fds))
1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      return -1;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Close the sending end of the socket right away so that if our peer closes
2005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // it before sending a response (e.g., from exiting), RecvMsgWithFlags() will
2015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // return EOF instead of hanging.
2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  send_sock.reset();
2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ScopedVector<base::ScopedFD> recv_fds;
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // sender might get a SIGPIPE.
2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const ssize_t reply_len = RecvMsgWithFlags(
2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      recv_sock.get(), reply, max_reply_len, recvmsg_flags, &recv_fds, NULL);
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  recv_sock.reset();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (reply_len == -1)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // If we received more file descriptors than caller expected, then we treat
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // that as an error.
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (recv_fds.size() > (result_fd != NULL ? 1 : 0)) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result_fd)
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    *result_fd = recv_fds.empty() ? -1 : recv_fds[0]->release();
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return reply_len;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
225