summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/chrome/common/ipc_channel_posix.h
blob: 1dfa33057520a58234abc464a7c3321eb06a1804 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_COMMON_IPC_CHANNEL_POSIX_H_
#define CHROME_COMMON_IPC_CHANNEL_POSIX_H_

#include "chrome/common/ipc_channel.h"

#include <sys/socket.h>  // for CMSG macros

#include <queue>
#include <string>
#include <vector>
#include <list>

#include "base/message_loop.h"
#include "base/task.h"
#include "chrome/common/file_descriptor_set_posix.h"

#include "nsAutoPtr.h"

#include "mozilla/Maybe.h"

namespace IPC {

// An implementation of ChannelImpl for POSIX systems that works via
// socketpairs.  See the .cc file for an overview of the implementation.
class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
 public:
  // Mirror methods of Channel, see ipc_channel.h for description.
  ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
  ChannelImpl(int fd, Mode mode, Listener* listener);
  ~ChannelImpl() { Close(); }
  bool Connect();
  void Close();
  Listener* set_listener(Listener* listener) {
    Listener* old = listener_;
    listener_ = listener;
    return old;
  }
  bool Send(Message* message);
  void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;

  void ResetFileDescriptor(int fd);

  int GetFileDescriptor() const {
      return pipe_;
  }
  void CloseClientFileDescriptor();

  // See the comment in ipc_channel.h for info on Unsound_IsClosed() and
  // Unsound_NumQueuedMessages().
  bool Unsound_IsClosed() const;
  uint32_t Unsound_NumQueuedMessages() const;

 private:
  void Init(Mode mode, Listener* listener);
  bool CreatePipe(const std::wstring& channel_id, Mode mode);
  bool EnqueueHelloMessage();

  bool ProcessIncomingMessages();
  bool ProcessOutgoingMessages();

  // MessageLoopForIO::Watcher implementation.
  virtual void OnFileCanReadWithoutBlocking(int fd);
  virtual void OnFileCanWriteWithoutBlocking(int fd);

#if defined(OS_MACOSX)
  void CloseDescriptors(uint32_t pending_fd_id);
#endif

  void OutputQueuePush(Message* msg);
  void OutputQueuePop();

  Mode mode_;

  // After accepting one client connection on our server socket we want to
  // stop listening.
  MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_;
  MessageLoopForIO::FileDescriptorWatcher read_watcher_;
  MessageLoopForIO::FileDescriptorWatcher write_watcher_;

  // Indicates whether we're currently blocked waiting for a write to complete.
  bool is_blocked_on_write_;

  // If sending a message blocks then we use this iterator to keep track of
  // where in the message we are. It gets reset when the message is finished
  // sending.
  mozilla::Maybe<Pickle::BufferList::IterImpl> partial_write_iter_;

  int server_listen_pipe_;
  int pipe_;
  int client_pipe_;  // The client end of our socketpair().

  // The "name" of our pipe.  On Windows this is the global identifier for
  // the pipe.  On POSIX it's used as a key in a local map of file descriptors.
  std::string pipe_name_;

  Listener* listener_;

  // Messages to be sent are queued here.
  std::queue<Message*> output_queue_;

  // We read from the pipe into this buffer
  char input_buf_[Channel::kReadBufferSize];
  size_t input_buf_offset_;

  // We want input_cmsg_buf_ to be big enough to hold
  // CMSG_SPACE(Channel::kReadBufferSize) bytes (see the comment below for an
  // explanation of where Channel::kReadBufferSize comes from). However,
  // CMSG_SPACE is apparently not a constant on Macs, so we can't use it in the
  // array size. Consequently, we pick a number here that is at least
  // CMSG_SPACE(0) on all platforms. And we assert at runtime, in
  // Channel::ChannelImpl::Init, that it's big enough.
  enum {
    kControlBufferSlopBytes = 32
  };

  // This is a control message buffer large enough to hold all the file
  // descriptors that will be read in when reading Channel::kReadBufferSize
  // bytes of data. Message::WriteFileDescriptor always writes one word of
  // data for every file descriptor added to the message, so kReadBufferSize
  // bytes of data can never be accompanied by more than
  // kReadBufferSize / sizeof(int) file descriptors. Since a file descriptor
  // takes sizeof(int) bytes, the control buffer must be
  // Channel::kReadBufferSize bytes. We add kControlBufferSlopBytes bytes
  // for the control header.
  char input_cmsg_buf_[Channel::kReadBufferSize + kControlBufferSlopBytes];

  // Large incoming messages that span multiple pipe buffers get built-up in the
  // buffers of this message.
  mozilla::Maybe<Message> incoming_message_;
  std::vector<int> input_overflow_fds_;

  // In server-mode, we have to wait for the client to connect before we
  // can begin reading.  We make use of the input_state_ when performing
  // the connect operation in overlapped mode.
  bool waiting_connect_;

  // This flag is set when processing incoming messages.  It is used to
  // avoid recursing through ProcessIncomingMessages, which could cause
  // problems.  TODO(darin): make this unnecessary
  bool processing_incoming_;

  // This flag is set after we've closed the channel.
  bool closed_;

#if defined(OS_MACOSX)
  struct PendingDescriptors {
    uint32_t id;
    RefPtr<FileDescriptorSet> fds;

    PendingDescriptors() : id(0) { }
    PendingDescriptors(uint32_t id, FileDescriptorSet *fds)
      : id(id),
        fds(fds)
    { }
  };

  std::list<PendingDescriptors> pending_fds_;

  // A generation ID for RECEIVED_FD messages.
  uint32_t last_pending_fd_id_;
#endif

  // This variable is updated so it matches output_queue_.size(), except we can
  // read output_queue_length_ from any thread (if we're OK getting an
  // occasional out-of-date or bogus value).  We use output_queue_length_ to
  // implement Unsound_NumQueuedMessages.
  size_t output_queue_length_;

  ScopedRunnableMethodFactory<ChannelImpl> factory_;

  DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
};

}  // namespace IPC

#endif  // CHROME_COMMON_IPC_CHANNEL_POSIX_H_