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. 4 5 #include "base/posix/unix_domain_socket_linux.h" 6 7 #include <errno.h> 8 #include <sys/socket.h> 9 #include <sys/uio.h> 10 #include <unistd.h> 11 12 #include "base/logging.h" 13 #include "base/pickle.h" 14 #include "base/posix/eintr_wrapper.h" 15 #include "base/stl_util.h" 16 17 const size_t UnixDomainSocket::kMaxFileDescriptors = 16; 18 19 // static 20 bool UnixDomainSocket::SendMsg(int fd, 21 const void* buf, 22 size_t length, 23 const std::vector<int>& fds) { 24 struct msghdr msg = {}; 25 struct iovec iov = { const_cast<void*>(buf), length }; 26 msg.msg_iov = &iov; 27 msg.msg_iovlen = 1; 28 29 char* control_buffer = NULL; 30 if (fds.size()) { 31 const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size()); 32 control_buffer = new char[control_len]; 33 34 struct cmsghdr* cmsg; 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; 43 } 44 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 48 // POSIX. 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; 53 return ret; 54 } 55 56 // static 57 ssize_t UnixDomainSocket::RecvMsg(int fd, 58 void* buf, 59 size_t length, 60 std::vector<int>* fds) { 61 return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds); 62 } 63 64 // static 65 ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd, 66 void* buf, 67 size_t length, 68 int flags, 69 std::vector<int>* fds) { 70 fds->clear(); 71 72 struct msghdr msg = {}; 73 struct iovec iov = { buf, length }; 74 msg.msg_iov = &iov; 75 msg.msg_iovlen = 1; 76 77 char control_buffer[CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)]; 78 msg.msg_control = control_buffer; 79 msg.msg_controllen = sizeof(control_buffer); 80 81 const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags)); 82 if (r == -1) 83 return -1; 84 85 int* wire_fds = NULL; 86 unsigned wire_fds_len = 0; 87 88 if (msg.msg_controllen > 0) { 89 struct cmsghdr* cmsg; 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); 97 break; 98 } 99 } 100 } 101 102 if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) { 103 for (unsigned i = 0; i < wire_fds_len; ++i) 104 close(wire_fds[i]); 105 errno = EMSGSIZE; 106 return -1; 107 } 108 109 fds->resize(wire_fds_len); 110 memcpy(vector_as_array(fds), wire_fds, sizeof(int) * wire_fds_len); 111 112 return r; 113 } 114 115 // static 116 ssize_t UnixDomainSocket::SendRecvMsg(int fd, 117 uint8_t* reply, 118 unsigned max_reply_len, 119 int* result_fd, 120 const Pickle& request) { 121 return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len, 122 0, /* recvmsg_flags */ 123 result_fd, request); 124 } 125 126 // static 127 ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd, 128 uint8_t* reply, 129 unsigned max_reply_len, 130 int recvmsg_flags, 131 int* result_fd, 132 const Pickle& request) { 133 int fds[2]; 134 135 // This socketpair is only used for the IPC and is cleaned up before 136 // returning. 137 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) == -1) 138 return -1; 139 140 std::vector<int> fd_vector; 141 fd_vector.push_back(fds[1]); 142 if (!SendMsg(fd, request.data(), request.size(), fd_vector)) { 143 close(fds[0]); 144 close(fds[1]); 145 return -1; 146 } 147 close(fds[1]); 148 149 fd_vector.clear(); 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); 154 close(fds[0]); 155 if (reply_len == -1) 156 return -1; 157 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) { 161 close(*i); 162 } 163 164 NOTREACHED(); 165 166 return -1; 167 } 168 169 if (result_fd) 170 *result_fd = fd_vector.empty() ? -1 : fd_vector[0]; 171 172 return reply_len; 173 } 174