summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/chrome/common/ipc_channel_win.h
blob: 5c141ebe34e83b194df2cdb4a12d51560ca7a465 (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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/* -*- 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_WIN_H_
#define CHROME_COMMON_IPC_CHANNEL_WIN_H_

#include "chrome/common/ipc_channel.h"
#include "chrome/common/ipc_channel_capability.h"
#include "chrome/common/ipc_message.h"

#include <atomic>
#include <string>

#include "base/message_loop.h"
#include "base/task.h"
#include "nsISupportsImpl.h"

#include "mozilla/EventTargetCapability.h"
#include "mozilla/Maybe.h"
#include "mozilla/Mutex.h"
#include "mozilla/Queue.h"
#include "mozilla/UniquePtr.h"

namespace IPC {

class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET(
      ChannelImpl, IOThread().GetEventTarget());

  using ChannelId = Channel::ChannelId;
  using ChannelHandle = Channel::ChannelHandle;

  // Mirror methods of Channel, see ipc_channel.h for description.
  ChannelImpl(const ChannelId& channel_id, Mode mode, Listener* listener);
  ChannelImpl(ChannelHandle pipe, Mode mode, Listener* listener);
  bool Connect() MOZ_EXCLUDES(SendMutex());
  void Close() MOZ_EXCLUDES(SendMutex());
  void StartAcceptingHandles(Mode mode) MOZ_EXCLUDES(SendMutex());
  Listener* set_listener(Listener* listener) {
    IOThread().AssertOnCurrentThread();
    chan_cap_.NoteOnIOThread();
    Listener* old = listener_;
    listener_ = listener;
    return old;
  }
  // NOTE: `Send` may be called on threads other than the I/O thread.
  bool Send(mozilla::UniquePtr<Message> message) MOZ_EXCLUDES(SendMutex());

  int32_t OtherPid() {
    IOThread().AssertOnCurrentThread();
    chan_cap_.NoteOnIOThread();
    return other_pid_;
  }

  // See the comment in ipc_channel.h for info on IsClosed()
  // NOTE: `IsClosed` may be called on threads other than the I/O thread.
  bool IsClosed() MOZ_EXCLUDES(SendMutex()) {
    mozilla::MutexAutoLock lock(SendMutex());
    chan_cap_.NoteSendMutex();
    return pipe_ == INVALID_HANDLE_VALUE;
  }

 private:
  ~ChannelImpl() {
    IOThread().AssertOnCurrentThread();
    if (pipe_ != INVALID_HANDLE_VALUE ||
        other_process_ != INVALID_HANDLE_VALUE) {
      Close();
    }
  }

  void Init(Mode mode, Listener* listener)
      MOZ_REQUIRES(SendMutex(), IOThread());

  void OutputQueuePush(mozilla::UniquePtr<Message> msg)
      MOZ_REQUIRES(SendMutex());
  void OutputQueuePop() MOZ_REQUIRES(SendMutex());

  const ChannelId PipeName(const ChannelId& channel_id, int32_t* secret) const;
  bool CreatePipe(const ChannelId& channel_id, Mode mode)
      MOZ_REQUIRES(SendMutex(), IOThread());
  void SetOtherPid(int other_pid) MOZ_REQUIRES(IOThread())
      MOZ_EXCLUDES(SendMutex());
  bool EnqueueHelloMessage() MOZ_REQUIRES(SendMutex(), IOThread());
  void CloseLocked() MOZ_REQUIRES(SendMutex(), IOThread());

  bool ProcessConnection() MOZ_REQUIRES(SendMutex(), IOThread());
  bool ProcessIncomingMessages(MessageLoopForIO::IOContext* context,
                               DWORD bytes_read, bool was_pending)
      MOZ_REQUIRES(IOThread());
  bool ProcessOutgoingMessages(MessageLoopForIO::IOContext* context,
                               DWORD bytes_written, bool was_pending)
      MOZ_REQUIRES(SendMutex());

  // Called on a Message immediately before it is sent/recieved to transfer
  // handles to the remote process, or accept handles from the remote process.
  bool AcceptHandles(Message& msg) MOZ_REQUIRES(IOThread());
  bool TransferHandles(Message& msg) MOZ_REQUIRES(SendMutex());

  // MessageLoop::IOHandler implementation.
  virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
                             DWORD bytes_transfered, DWORD error);

  const ChannelCapability::Thread& IOThread() const
      MOZ_RETURN_CAPABILITY(chan_cap_.IOThread()) {
    return chan_cap_.IOThread();
  }

  ChannelCapability::Mutex& SendMutex()
      MOZ_RETURN_CAPABILITY(chan_cap_.SendMutex()) {
    return chan_cap_.SendMutex();
  }

 private:
  // Compound capability of a Mutex and the IO thread.
  ChannelCapability chan_cap_;

  Mode mode_ MOZ_GUARDED_BY(IOThread());

  struct State {
    explicit State(ChannelImpl* channel);
    ~State();
    MessageLoopForIO::IOContext context;
    // When there is pending I/O, this holds a strong reference to the
    // ChannelImpl to prevent it from going away.
    RefPtr<ChannelImpl> is_pending;
  };

  State input_state_ MOZ_GUARDED_BY(IOThread());
  State output_state_ MOZ_GUARDED_BY(SendMutex());

  HANDLE pipe_ MOZ_GUARDED_BY(chan_cap_) = INVALID_HANDLE_VALUE;

  Listener* listener_ MOZ_GUARDED_BY(IOThread()) = nullptr;

  // Messages to be sent are queued here.
  mozilla::Queue<mozilla::UniquePtr<Message>, 64> output_queue_
      MOZ_GUARDED_BY(SendMutex());

  // 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_
      MOZ_GUARDED_BY(SendMutex());

  // We read from the pipe into this buffer
  mozilla::UniquePtr<char[]> input_buf_ MOZ_GUARDED_BY(IOThread());
  size_t input_buf_offset_ MOZ_GUARDED_BY(IOThread()) = 0;

  // Large incoming messages that span multiple pipe buffers get built-up in the
  // buffers of this message.
  mozilla::UniquePtr<Message> incoming_message_ MOZ_GUARDED_BY(IOThread());

  // Timer started when a MODE_SERVER channel begins waiting for a connection,
  // and cancelled when the connection completes. Will produce an error if no
  // connection occurs before the timeout.
  nsCOMPtr<nsITimer> connect_timeout_ MOZ_GUARDED_BY(IOThread());

  // Will be set to `true` until `Connect()` has been called, and, if in
  // server-mode, the client has connected. The `input_state_` is used to wait
  // for the client to connect in overlapped mode.
  bool waiting_connect_ MOZ_GUARDED_BY(chan_cap_) = true;

  // 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_ MOZ_GUARDED_BY(IOThread()) = false;

  // We keep track of the PID of the other side of this channel so that we can
  // record this when generating logs of IPC messages.
  int32_t other_pid_ MOZ_GUARDED_BY(chan_cap_) = -1;

  // This is a unique per-channel value used to authenticate the client end of
  // a connection. If the value is non-zero, the client passes it in the hello
  // and the host validates. (We don't send the zero value to preserve IPC
  // compatibility with existing clients that don't validate the channel.)
  int32_t shared_secret_ MOZ_GUARDED_BY(IOThread()) = 0;

  // In server-mode, we wait for the channel at the other side of the pipe to
  // send us back our shared secret, if we are using one.
  bool waiting_for_shared_secret_ MOZ_GUARDED_BY(IOThread()) = false;

  // Whether or not to accept handles from a remote process, and whether this
  // process is the privileged side of a IPC::Channel which can transfer
  // handles.
  bool accept_handles_ MOZ_GUARDED_BY(chan_cap_) = false;
  bool privileged_ MOZ_GUARDED_BY(chan_cap_) = false;

  // A privileged process handle used to transfer HANDLEs to and from the remote
  // process. This will only be used if `privileged_` is set.
  HANDLE other_process_ MOZ_GUARDED_BY(chan_cap_) = INVALID_HANDLE_VALUE;

  DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
};

}  // namespace IPC

#endif  // CHROME_COMMON_IPC_CHANNEL_WIN_H_