1 // Copyright 2014 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 "mojo/edk/embedder/platform_channel_utils_posix.h" 6 7 #include <stddef.h> 8 #include <sys/socket.h> 9 #include <unistd.h> 10 11 #include "base/logging.h" 12 #include "base/posix/eintr_wrapper.h" 13 #include "build/build_config.h" 14 15 #if !defined(OS_NACL) 16 #include <sys/uio.h> 17 #endif 18 19 #if !defined(SO_PEEK_OFF) 20 #define SO_PEEK_OFF 42 21 #endif 22 23 namespace mojo { 24 namespace edk { 25 26 // On Linux, |SIGPIPE| is suppressed by passing |MSG_NOSIGNAL| to 27 // |send()|/|sendmsg()|. (There is no way of suppressing |SIGPIPE| on 28 // |write()|/|writev().) On Mac, |SIGPIPE| is suppressed by setting the 29 // |SO_NOSIGPIPE| option on the socket. 30 // 31 // Performance notes: 32 // - On Linux, we have to use |send()|/|sendmsg()| rather than 33 // |write()|/|writev()| in order to suppress |SIGPIPE|. This is okay, since 34 // |send()| is (slightly) faster than |write()| (!), while |sendmsg()| is 35 // quite comparable to |writev()|. 36 // - On Mac, we may use |write()|/|writev()|. Here, |write()| is considerably 37 // faster than |send()|, whereas |sendmsg()| is quite comparable to 38 // |writev()|. 39 // - On both platforms, an appropriate |sendmsg()|/|writev()| is considerably 40 // faster than two |send()|s/|write()|s. 41 // - Relative numbers (minimum real times from 10 runs) for one |write()| of 42 // 1032 bytes, one |send()| of 1032 bytes, one |writev()| of 32+1000 bytes, 43 // one |sendmsg()| of 32+1000 bytes, two |write()|s of 32 and 1000 bytes, two 44 // |send()|s of 32 and 1000 bytes: 45 // - Linux: 0.81 s, 0.77 s, 0.87 s, 0.89 s, 1.31 s, 1.22 s 46 // - Mac: 2.21 s, 2.91 s, 2.98 s, 3.08 s, 3.59 s, 4.74 s 47 48 // Flags to use with calling |send()| or |sendmsg()| (see above). 49 #if defined(OS_MACOSX) 50 const int kSendFlags = 0; 51 #else 52 const int kSendFlags = MSG_NOSIGNAL; 53 #endif 54 55 ssize_t PlatformChannelWrite(PlatformHandle h, 56 const void* bytes, 57 size_t num_bytes) { 58 DCHECK(h.is_valid()); 59 DCHECK(bytes); 60 DCHECK_GT(num_bytes, 0u); 61 62 #if defined(OS_MACOSX) || defined(OS_NACL_NONSFI) 63 // send() is not available under NaCl-nonsfi. 64 return HANDLE_EINTR(write(h.handle, bytes, num_bytes)); 65 #else 66 return send(h.handle, bytes, num_bytes, kSendFlags); 67 #endif 68 } 69 70 ssize_t PlatformChannelWritev(PlatformHandle h, 71 struct iovec* iov, 72 size_t num_iov) { 73 DCHECK(h.is_valid()); 74 DCHECK(iov); 75 DCHECK_GT(num_iov, 0u); 76 77 #if defined(OS_MACOSX) 78 return HANDLE_EINTR(writev(h.handle, iov, static_cast<int>(num_iov))); 79 #else 80 struct msghdr msg = {}; 81 msg.msg_iov = iov; 82 msg.msg_iovlen = num_iov; 83 return HANDLE_EINTR(sendmsg(h.handle, &msg, kSendFlags)); 84 #endif 85 } 86 87 ssize_t PlatformChannelSendmsgWithHandles(PlatformHandle h, 88 struct iovec* iov, 89 size_t num_iov, 90 PlatformHandle* platform_handles, 91 size_t num_platform_handles) { 92 DCHECK(iov); 93 DCHECK_GT(num_iov, 0u); 94 DCHECK(platform_handles); 95 DCHECK_GT(num_platform_handles, 0u); 96 DCHECK_LE(num_platform_handles, kPlatformChannelMaxNumHandles); 97 98 char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))]; 99 struct msghdr msg = {}; 100 msg.msg_iov = iov; 101 msg.msg_iovlen = num_iov; 102 msg.msg_control = cmsg_buf; 103 msg.msg_controllen = CMSG_LEN(num_platform_handles * sizeof(int)); 104 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); 105 cmsg->cmsg_level = SOL_SOCKET; 106 cmsg->cmsg_type = SCM_RIGHTS; 107 cmsg->cmsg_len = CMSG_LEN(num_platform_handles * sizeof(int)); 108 for (size_t i = 0; i < num_platform_handles; i++) { 109 DCHECK(platform_handles[i].is_valid()); 110 reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] = platform_handles[i].handle; 111 } 112 113 return HANDLE_EINTR(sendmsg(h.handle, &msg, kSendFlags)); 114 } 115 116 bool PlatformChannelSendHandles(PlatformHandle h, 117 PlatformHandle* handles, 118 size_t num_handles) { 119 DCHECK(handles); 120 DCHECK_GT(num_handles, 0u); 121 DCHECK_LE(num_handles, kPlatformChannelMaxNumHandles); 122 123 // Note: |sendmsg()| fails on Mac if we don't write at least one character. 124 struct iovec iov = {const_cast<char*>(""), 1}; 125 char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))]; 126 struct msghdr msg = {}; 127 msg.msg_iov = &iov; 128 msg.msg_iovlen = 1; 129 msg.msg_control = cmsg_buf; 130 msg.msg_controllen = CMSG_LEN(num_handles * sizeof(int)); 131 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); 132 cmsg->cmsg_level = SOL_SOCKET; 133 cmsg->cmsg_type = SCM_RIGHTS; 134 cmsg->cmsg_len = CMSG_LEN(num_handles * sizeof(int)); 135 for (size_t i = 0; i < num_handles; i++) { 136 DCHECK(handles[i].is_valid()); 137 reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] = handles[i].handle; 138 } 139 140 ssize_t result = HANDLE_EINTR(sendmsg(h.handle, &msg, kSendFlags)); 141 if (result < 1) { 142 DCHECK_EQ(result, -1); 143 return false; 144 } 145 146 for (size_t i = 0; i < num_handles; i++) 147 handles[i].CloseIfNecessary(); 148 return true; 149 } 150 151 ssize_t PlatformChannelRecvmsg(PlatformHandle h, 152 void* buf, 153 size_t num_bytes, 154 std::deque<PlatformHandle>* platform_handles, 155 bool block) { 156 DCHECK(buf); 157 DCHECK_GT(num_bytes, 0u); 158 DCHECK(platform_handles); 159 160 struct iovec iov = {buf, num_bytes}; 161 char cmsg_buf[CMSG_SPACE(kPlatformChannelMaxNumHandles * sizeof(int))]; 162 struct msghdr msg = {}; 163 msg.msg_iov = &iov; 164 msg.msg_iovlen = 1; 165 msg.msg_control = cmsg_buf; 166 msg.msg_controllen = sizeof(cmsg_buf); 167 168 ssize_t result = 169 HANDLE_EINTR(recvmsg(h.handle, &msg, block ? 0 : MSG_DONTWAIT)); 170 if (result < 0) 171 return result; 172 173 // Success; no control messages. 174 if (msg.msg_controllen == 0) 175 return result; 176 177 DCHECK(!(msg.msg_flags & MSG_CTRUNC)); 178 179 for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; 180 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 181 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { 182 size_t payload_length = cmsg->cmsg_len - CMSG_LEN(0); 183 DCHECK_EQ(payload_length % sizeof(int), 0u); 184 size_t num_fds = payload_length / sizeof(int); 185 const int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); 186 for (size_t i = 0; i < num_fds; i++) { 187 platform_handles->push_back(PlatformHandle(fds[i])); 188 DCHECK(platform_handles->back().is_valid()); 189 } 190 } 191 } 192 193 return result; 194 } 195 196 } // namespace edk 197 } // namespace mojo 198