ipc_channel_posix.h revision 9ab5563a3196760eb381d102cbb2bc0f7abc6a50
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 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)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef IPC_IPC_CHANNEL_POSIX_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IPC_IPC_CHANNEL_POSIX_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_channel.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>  // for CMSG macros
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <queue>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/process.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/file_descriptor_set_posix.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_channel_reader.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(OS_MACOSX)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On Linux, the seccomp sandbox makes it very expensive to call
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recvmsg() and sendmsg(). The restriction on calling read() and write(), which
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are cheap, is that we can't pass file descriptors over them.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// As we cannot anticipate when the sender will provide us with file
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// descriptors, we have to make the decision about whether we call read() or
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recvmsg() before we actually make the call. The easiest option is to
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// create a dedicated socketpair() for exchanging file descriptors. Any file
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// descriptors are split out of a message, with the non-file-descriptor payload
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// going over the normal connection, and the file descriptors being sent
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// separately over the other channel. When read()ing from a channel, we'll
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice if the message was supposed to have come with file descriptors and
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use recvmsg on the other socketpair to retrieve them and combine them
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// back with the rest of the message.
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mac can also run in IPC_USES_READWRITE mode if necessary, but at this time
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// doesn't take a performance hit from recvmsg and sendmsg, so it doesn't
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// make sense to waste resources on having the separate dedicated socketpair.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is however useful for debugging between Linux and Mac to be able to turn
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this switch 'on' on the Mac as well.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The HELLO message from the client to the server is always sent using
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// sendmsg because it will contain the file descriptor that the server
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// needs to send file descriptors in later messages.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define IPC_USES_READWRITE 1
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace IPC {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Channel::ChannelImpl : public internal::ChannelReader,
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                             public base::MessageLoopForIO::Watcher {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mirror methods of Channel, see ipc_channel.h for description.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ChannelImpl(const IPC::ChannelHandle& channel_handle, Mode mode,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              Listener* listener);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ChannelImpl();
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Connect();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Close();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Send(Message* message);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int GetClientFileDescriptor();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int TakeClientFileDescriptor();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CloseClientFileDescriptor();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool AcceptsConnections() const;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool HasAcceptedConnection() const;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool GetPeerEuid(uid_t* peer_euid) const;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ResetToAcceptingConnectionState();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ProcessId peer_pid() const { return peer_pid_; }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool IsNamedServerInitialized(const std::string& channel_id);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static void SetGlobalPid(int pid);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_LINUX
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool CreatePipe(const IPC::ChannelHandle& channel_handle);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ProcessOutgoingMessages();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool AcceptConnection();
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ClosePipeOnError();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int GetHelloMessageProcId();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void QueueHelloMessage();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ChannelReader implementation.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ReadState ReadData(char* buffer,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int buffer_len,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             int* bytes_read) OVERRIDE;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool WillDispatchInputMessage(Message* msg) OVERRIDE;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual bool DidEmptyInputBuffers() OVERRIDE;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void HandleHelloMessage(const Message& msg) OVERRIDE;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(IPC_USES_READWRITE)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Reads the next message from the fd_pipe_ and appends them to the
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // input_fds_ queue. Returns false if there was a message receiving error.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True means there was a message and it was processed properly, or there was
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // no messages.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ReadFileDescriptorsFromFDPipe();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Finds the set of file descriptors in the given message.  On success,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // appends the descriptors to the input_fds_ member and returns true
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Returns false if the message was truncated. In this case, any handles that
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // were sent will be closed.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool ExtractFileDescriptorsFromMsghdr(msghdr* msg);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Closes all handles in the input_fds_ list and clears the list. This is
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used to clean up handles in error conditions to avoid leaking the handles.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void ClearInputFDs();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MessageLoopForIO::Watcher implementation.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Mode mode_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ProcessId peer_pid_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After accepting one client connection on our server socket we want to
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // stop listening.
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoopForIO::FileDescriptorWatcher
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  server_listen_connection_watcher_;
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoopForIO::FileDescriptorWatcher read_watcher_;
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoopForIO::FileDescriptorWatcher write_watcher_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicates whether we're currently blocked waiting for a write to complete.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool is_blocked_on_write_;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool waiting_connect_;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If sending a message blocks then we use this variable
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to keep track of where we are.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t message_send_bytes_written_;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // File descriptor we're listening on for new connections if we listen
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // for connections.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int server_listen_pipe_;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The pipe used for communication.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pipe_;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For a server, the client end of our socketpair() -- the other end of our
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // pipe_ that is passed to the client.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int client_pipe_;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock client_pipe_lock_;  // Lock that protects |client_pipe_|.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(IPC_USES_READWRITE)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Linux/BSD use a dedicated socketpair() for passing file descriptors.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int fd_pipe_;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int remote_fd_pipe_;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The "name" of our pipe.  On Windows this is the global identifier for
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the pipe.  On POSIX it's used as a key in a local map of file descriptors.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string pipe_name_;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Messages to be sent are queued here.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::queue<Message*> output_queue_;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We assume a worst case: kReadBufferSize bytes of messages, where each
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message has no payload and a full complement of descriptors.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kMaxReadFDs =
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) *
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FileDescriptorSet::kMaxDescriptorsPerMessage;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Buffer size for file descriptors used for recvmsg. On Mac the CMSG macros
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't seem to be constant so we have to pick a "large enough" value.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kMaxReadFDBuffer = 1024;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const size_t kMaxReadFDBuffer = CMSG_SPACE(sizeof(int) * kMaxReadFDs);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Temporary buffer used to receive the file descriptors from recvmsg.
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Code that writes into this should immediately read them out and save
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // them to input_fds_, since this buffer will be re-used anytime we call
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // recvmsg.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char input_cmsg_buf_[kMaxReadFDBuffer];
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // File descriptors extracted from messages coming off of the channel. The
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // handles may span messages and come off different channels from the message
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // data (in the case of READWRITE), and are processed in FIFO here.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NOTE: The implementation assumes underlying storage here is contiguous, so
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // don't change to something like std::deque<> without changing the
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // implementation!
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<int> input_fds_;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // True if we are responsible for unlinking the unix domain socket file.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool must_unlink_;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If non-zero, overrides the process ID sent in the hello message.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static int global_pid_;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // OS_LINUX
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace IPC
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // IPC_IPC_CHANNEL_POSIX_H_
201