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.
5 #include "mojo/embedder/platform_channel_utils_posix.h"
7 #include <sys/socket.h>
11 #include "base/logging.h"
12 #include "base/posix/eintr_wrapper.h"
13 #include "build/build_config.h"
18 // On Linux, |SIGPIPE| is suppressed by passing |MSG_NOSIGNAL| to
19 // |send()|/|sendmsg()|. (There is no way of suppressing |SIGPIPE| on
20 // |write()|/|writev().) On Mac, |SIGPIPE| is suppressed by setting the
21 // |SO_NOSIGPIPE| option on the socket.
24 // - On Linux, we have to use |send()|/|sendmsg()| rather than
25 // |write()|/|writev()| in order to suppress |SIGPIPE|. This is okay, since
26 // |send()| is (slightly) faster than |write()| (!), while |sendmsg()| is
27 // quite comparable to |writev()|.
28 // - On Mac, we may use |write()|/|writev()|. Here, |write()| is considerably
29 // faster than |send()|, whereas |sendmsg()| is quite comparable to
31 // - On both platforms, an appropriate |sendmsg()|/|writev()| is considerably
32 // faster than two |send()|s/|write()|s.
33 // - Relative numbers (minimum real times from 10 runs) for one |write()| of
34 // 1032 bytes, one |send()| of 1032 bytes, one |writev()| of 32+1000 bytes,
35 // one |sendmsg()| of 32+1000 bytes, two |write()|s of 32 and 1000 bytes, two
36 // |send()|s of 32 and 1000 bytes:
37 // - Linux: 0.81 s, 0.77 s, 0.87 s, 0.89 s, 1.31 s, 1.22 s
38 // - Mac: 2.21 s, 2.91 s, 2.98 s, 3.08 s, 3.59 s, 4.74 s
40 // Flags to use with calling |send()| or |sendmsg()| (see above).
41 #if defined(OS_MACOSX)
42 const int kSendFlags
= 0;
44 const int kSendFlags
= MSG_NOSIGNAL
;
47 ssize_t
PlatformChannelWrite(PlatformHandle h
,
52 DCHECK_GT(num_bytes
, 0u);
54 #if defined(OS_MACOSX)
55 return HANDLE_EINTR(write(h
.fd
, bytes
, num_bytes
));
57 return send(h
.fd
, bytes
, num_bytes
, kSendFlags
);
61 ssize_t
PlatformChannelWritev(PlatformHandle h
,
66 DCHECK_GT(num_iov
, 0u);
68 #if defined(OS_MACOSX)
69 return HANDLE_EINTR(writev(h
.fd
, iov
, static_cast<int>(num_iov
)));
71 struct msghdr msg
= {};
73 msg
.msg_iovlen
= num_iov
;
74 return HANDLE_EINTR(sendmsg(h
.fd
, &msg
, kSendFlags
));
78 ssize_t
PlatformChannelSendmsgWithHandles(PlatformHandle h
,
81 PlatformHandle
* platform_handles
,
82 size_t num_platform_handles
) {
84 DCHECK_GT(num_iov
, 0u);
85 DCHECK(platform_handles
);
86 DCHECK_GT(num_platform_handles
, 0u);
87 DCHECK_LE(num_platform_handles
, kPlatformChannelMaxNumHandles
);
89 char cmsg_buf
[CMSG_SPACE(kPlatformChannelMaxNumHandles
* sizeof(int))];
90 struct msghdr msg
= {};
92 msg
.msg_iovlen
= num_iov
;
93 msg
.msg_control
= cmsg_buf
;
94 msg
.msg_controllen
= CMSG_LEN(num_platform_handles
* sizeof(int));
95 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
96 cmsg
->cmsg_level
= SOL_SOCKET
;
97 cmsg
->cmsg_type
= SCM_RIGHTS
;
98 cmsg
->cmsg_len
= CMSG_LEN(num_platform_handles
* sizeof(int));
99 for (size_t i
= 0; i
< num_platform_handles
; i
++) {
100 DCHECK(platform_handles
[i
].is_valid());
101 reinterpret_cast<int*>(CMSG_DATA(cmsg
))[i
] = platform_handles
[i
].fd
;
104 return HANDLE_EINTR(sendmsg(h
.fd
, &msg
, kSendFlags
));
107 bool PlatformChannelSendHandles(PlatformHandle h
,
108 PlatformHandle
* handles
,
109 size_t num_handles
) {
111 DCHECK_GT(num_handles
, 0u);
112 DCHECK_LE(num_handles
, kPlatformChannelMaxNumHandles
);
114 // Note: |sendmsg()| fails on Mac if we don't write at least one character.
115 struct iovec iov
= {const_cast<char*>(""), 1};
116 char cmsg_buf
[CMSG_SPACE(kPlatformChannelMaxNumHandles
* sizeof(int))];
117 struct msghdr msg
= {};
120 msg
.msg_control
= cmsg_buf
;
121 msg
.msg_controllen
= CMSG_LEN(num_handles
* sizeof(int));
122 struct cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
);
123 cmsg
->cmsg_level
= SOL_SOCKET
;
124 cmsg
->cmsg_type
= SCM_RIGHTS
;
125 cmsg
->cmsg_len
= CMSG_LEN(num_handles
* sizeof(int));
126 for (size_t i
= 0; i
< num_handles
; i
++) {
127 DCHECK(handles
[i
].is_valid());
128 reinterpret_cast<int*>(CMSG_DATA(cmsg
))[i
] = handles
[i
].fd
;
131 ssize_t result
= HANDLE_EINTR(sendmsg(h
.fd
, &msg
, kSendFlags
));
133 DCHECK_EQ(result
, -1);
137 for (size_t i
= 0; i
< num_handles
; i
++)
138 handles
[i
].CloseIfNecessary();
142 ssize_t
PlatformChannelRecvmsg(PlatformHandle h
,
145 std::deque
<PlatformHandle
>* platform_handles
) {
147 DCHECK_GT(num_bytes
, 0u);
148 DCHECK(platform_handles
);
150 struct iovec iov
= {buf
, num_bytes
};
151 char cmsg_buf
[CMSG_SPACE(kPlatformChannelMaxNumHandles
* sizeof(int))];
152 struct msghdr msg
= {};
155 msg
.msg_control
= cmsg_buf
;
156 msg
.msg_controllen
= sizeof(cmsg_buf
);
158 ssize_t result
= HANDLE_EINTR(recvmsg(h
.fd
, &msg
, MSG_DONTWAIT
));
162 // Success; no control messages.
163 if (msg
.msg_controllen
== 0)
166 DCHECK(!(msg
.msg_flags
& MSG_CTRUNC
));
168 for (cmsghdr
* cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
169 cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
170 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_RIGHTS
) {
171 size_t payload_length
= cmsg
->cmsg_len
- CMSG_LEN(0);
172 DCHECK_EQ(payload_length
% sizeof(int), 0u);
173 size_t num_fds
= payload_length
/ sizeof(int);
174 const int* fds
= reinterpret_cast<int*>(CMSG_DATA(cmsg
));
175 for (size_t i
= 0; i
< num_fds
; i
++) {
176 platform_handles
->push_back(PlatformHandle(fds
[i
]));
177 DCHECK(platform_handles
->back().is_valid());
185 } // namespace embedder