blob: aaefe158261539d751200cecada9b7fcade98306 [file] [log] [blame]
brettw@chromium.org293988a2012-03-01 07:48:14 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef IPC_IPC_CHANNEL_POSIX_H_
6#define IPC_IPC_CHANNEL_POSIX_H_
7
8#include "ipc/ipc_channel.h"
9
10#include <sys/socket.h> // for CMSG macros
11
12#include <queue>
13#include <string>
14#include <vector>
15
16#include "base/message_loop.h"
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +090017#include "base/process.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090018#include "ipc/file_descriptor_set_posix.h"
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090019#include "ipc/ipc_channel_reader.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090020
dmaclach@chromium.org2680d3a2010-12-09 06:22:24 +090021#if !defined(OS_MACOSX)
22// On Linux, the seccomp sandbox makes it very expensive to call
23// recvmsg() and sendmsg(). The restriction on calling read() and write(), which
24// are cheap, is that we can't pass file descriptors over them.
25//
26// As we cannot anticipate when the sender will provide us with file
27// descriptors, we have to make the decision about whether we call read() or
28// recvmsg() before we actually make the call. The easiest option is to
brettw@chromium.org0d7e0192011-05-14 04:22:14 +090029// create a dedicated socketpair() for exchanging file descriptors. Any file
30// descriptors are split out of a message, with the non-file-descriptor payload
31// going over the normal connection, and the file descriptors being sent
32// separately over the other channel. When read()ing from a channel, we'll
33// notice if the message was supposed to have come with file descriptors and
34// use recvmsg on the other socketpair to retrieve them and combine them
35// back with the rest of the message.
36//
dmaclach@chromium.org2680d3a2010-12-09 06:22:24 +090037// Mac can also run in IPC_USES_READWRITE mode if necessary, but at this time
38// doesn't take a performance hit from recvmsg and sendmsg, so it doesn't
39// make sense to waste resources on having the separate dedicated socketpair.
40// It is however useful for debugging between Linux and Mac to be able to turn
41// this switch 'on' on the Mac as well.
brettw@chromium.org0d7e0192011-05-14 04:22:14 +090042//
dmaclach@chromium.org2680d3a2010-12-09 06:22:24 +090043// The HELLO message from the client to the server is always sent using
44// sendmsg because it will contain the file descriptor that the server
45// needs to send file descriptors in later messages.
46#define IPC_USES_READWRITE 1
47#endif
48
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090049namespace IPC {
50
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090051class Channel::ChannelImpl : public internal::ChannelReader,
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +090052 public base::MessageLoopForIO::Watcher {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090053 public:
54 // Mirror methods of Channel, see ipc_channel.h for description.
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +090055 ChannelImpl(const IPC::ChannelHandle& channel_handle, Mode mode,
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +090056 Listener* listener);
hans@chromium.org78b75932011-05-25 18:08:19 +090057 virtual ~ChannelImpl();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090058 bool Connect();
59 void Close();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090060 bool Send(Message* message);
phajdan.jr@chromium.orgaf9455b2011-09-20 02:08:12 +090061 int GetClientFileDescriptor();
62 int TakeClientFileDescriptor();
63 void CloseClientFileDescriptor();
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +090064 bool AcceptsConnections() const;
65 bool HasAcceptedConnection() const;
jeremya@chromium.orgf14bfab2013-03-13 13:23:10 +090066 bool GetPeerEuid(uid_t* peer_euid) const;
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +090067 void ResetToAcceptingConnectionState();
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +090068 base::ProcessId peer_pid() const { return peer_pid_; }
kkania@chromium.orgf37b4e52011-08-09 15:46:06 +090069 static bool IsNamedServerInitialized(const std::string& channel_id);
jamescook@chromium.org2d471f02011-09-01 06:11:04 +090070#if defined(OS_LINUX)
71 static void SetGlobalPid(int pid);
72#endif // OS_LINUX
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090073
74 private:
dmaclach@chromium.orgf146c292011-02-04 05:35:09 +090075 bool CreatePipe(const IPC::ChannelHandle& channel_handle);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090076
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090077 bool ProcessOutgoingMessages();
78
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +090079 bool AcceptConnection();
80 void ClosePipeOnError();
jamescook@chromium.org2d471f02011-09-01 06:11:04 +090081 int GetHelloMessageProcId();
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +090082 void QueueHelloMessage();
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +090083
brettw@chromium.org0e9d0a12012-03-08 21:30:28 +090084 // ChannelReader implementation.
85 virtual ReadState ReadData(char* buffer,
86 int buffer_len,
87 int* bytes_read) OVERRIDE;
88 virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE;
89 virtual bool DidEmptyInputBuffers() OVERRIDE;
90 virtual void HandleHelloMessage(const Message& msg) OVERRIDE;
brettw@chromium.org293988a2012-03-01 07:48:14 +090091
92#if defined(IPC_USES_READWRITE)
93 // Reads the next message from the fd_pipe_ and appends them to the
94 // input_fds_ queue. Returns false if there was a message receiving error.
95 // True means there was a message and it was processed properly, or there was
96 // no messages.
97 bool ReadFileDescriptorsFromFDPipe();
98#endif
99
brettw@chromium.org293988a2012-03-01 07:48:14 +0900100 // Finds the set of file descriptors in the given message. On success,
101 // appends the descriptors to the input_fds_ member and returns true
102 //
103 // Returns false if the message was truncated. In this case, any handles that
104 // were sent will be closed.
105 bool ExtractFileDescriptorsFromMsghdr(msghdr* msg);
106
107 // Closes all handles in the input_fds_ list and clears the list. This is
108 // used to clean up handles in error conditions to avoid leaking the handles.
109 void ClearInputFDs();
110
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900111 // MessageLoopForIO::Watcher implementation.
avi@chromium.org362c8a82011-11-18 01:09:44 +0900112 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
113 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900114
115 Mode mode_;
116
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +0900117 base::ProcessId peer_pid_;
118
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900119 // After accepting one client connection on our server socket we want to
120 // stop listening.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900121 base::MessageLoopForIO::FileDescriptorWatcher
122 server_listen_connection_watcher_;
123 base::MessageLoopForIO::FileDescriptorWatcher read_watcher_;
124 base::MessageLoopForIO::FileDescriptorWatcher write_watcher_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900125
126 // Indicates whether we're currently blocked waiting for a write to complete.
127 bool is_blocked_on_write_;
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +0900128 bool waiting_connect_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900129
130 // If sending a message blocks then we use this variable
131 // to keep track of where we are.
132 size_t message_send_bytes_written_;
133
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +0900134 // File descriptor we're listening on for new connections if we listen
135 // for connections.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900136 int server_listen_pipe_;
137
138 // The pipe used for communication.
139 int pipe_;
140
141 // For a server, the client end of our socketpair() -- the other end of our
142 // pipe_ that is passed to the client.
143 int client_pipe_;
phajdan.jr@chromium.orgaf9455b2011-09-20 02:08:12 +0900144 base::Lock client_pipe_lock_; // Lock that protects |client_pipe_|.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900145
dmaclach@chromium.org2680d3a2010-12-09 06:22:24 +0900146#if defined(IPC_USES_READWRITE)
pvalchev@google.comc45765a2010-05-20 03:17:53 +0900147 // Linux/BSD use a dedicated socketpair() for passing file descriptors.
agl@chromium.orga81f84a2009-09-05 06:34:05 +0900148 int fd_pipe_;
149 int remote_fd_pipe_;
150#endif
151
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900152 // The "name" of our pipe. On Windows this is the global identifier for
153 // the pipe. On POSIX it's used as a key in a local map of file descriptors.
154 std::string pipe_name_;
155
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900156 // Messages to be sent are queued here.
157 std::queue<Message*> output_queue_;
158
pkasting@chromium.org9687a8f2011-09-01 09:50:13 +0900159 // We assume a worst case: kReadBufferSize bytes of messages, where each
160 // message has no payload and a full complement of descriptors.
161 static const size_t kMaxReadFDs =
162 (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) *
163 FileDescriptorSet::kMaxDescriptorsPerMessage;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900164
brettw@chromium.org293988a2012-03-01 07:48:14 +0900165 // Buffer size for file descriptors used for recvmsg. On Mac the CMSG macros
166 // don't seem to be constant so we have to pick a "large enough" value.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900167#if defined(OS_MACOSX)
brettw@chromium.org293988a2012-03-01 07:48:14 +0900168 static const size_t kMaxReadFDBuffer = 1024;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900169#else
brettw@chromium.org293988a2012-03-01 07:48:14 +0900170 static const size_t kMaxReadFDBuffer = CMSG_SPACE(sizeof(int) * kMaxReadFDs);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900171#endif
172
brettw@chromium.org293988a2012-03-01 07:48:14 +0900173 // Temporary buffer used to receive the file descriptors from recvmsg.
174 // Code that writes into this should immediately read them out and save
175 // them to input_fds_, since this buffer will be re-used anytime we call
176 // recvmsg.
177 char input_cmsg_buf_[kMaxReadFDBuffer];
178
179 // File descriptors extracted from messages coming off of the channel. The
180 // handles may span messages and come off different channels from the message
181 // data (in the case of READWRITE), and are processed in FIFO here.
fischman@chromium.org8b60dfa2012-04-10 06:40:44 +0900182 // NOTE: The implementation assumes underlying storage here is contiguous, so
183 // don't change to something like std::deque<> without changing the
184 // implementation!
185 std::vector<int> input_fds_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900186
dmaclach@chromium.orgc1d3d422010-12-20 15:59:23 +0900187 // True if we are responsible for unlinking the unix domain socket file.
188 bool must_unlink_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900189
jamescook@chromium.org2d471f02011-09-01 06:11:04 +0900190#if defined(OS_LINUX)
191 // If non-zero, overrides the process ID sent in the hello message.
192 static int global_pid_;
193#endif // OS_LINUX
194
dmaclach@chromium.org2812db62011-03-03 07:27:14 +0900195 DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900196};
197
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900198} // namespace IPC
199
200#endif // IPC_IPC_CHANNEL_POSIX_H_