Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ipc / ipc_channel_win.cc
1 // Copyright (c) 2012 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.
4
5 #include "ipc/ipc_channel_win.h"
6
7 #include <windows.h>
8
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/compiler_specific.h"
12 #include "base/logging.h"
13 #include "base/pickle.h"
14 #include "base/process/process_handle.h"
15 #include "base/rand_util.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread_checker.h"
19 #include "base/win/scoped_handle.h"
20 #include "ipc/ipc_listener.h"
21 #include "ipc/ipc_logging.h"
22 #include "ipc/ipc_message_utils.h"
23
24 namespace {
25
26 enum DebugFlags {
27   INIT_DONE = 1 << 0,
28   CALLED_CONNECT = 1 << 1,
29   PENDING_CONNECT = 1 << 2,
30   CONNECT_COMPLETED = 1 << 3,
31   PIPE_CONNECTED = 1 << 4,
32   WRITE_MSG = 1 << 5,
33   READ_MSG = 1 << 6,
34   WRITE_COMPLETED = 1 << 7,
35   READ_COMPLETED = 1 << 8,
36   CLOSED = 1 << 9,
37   WAIT_FOR_READ = 1 << 10,
38   WAIT_FOR_WRITE = 1 << 11,
39   WAIT_FOR_READ_COMPLETE = 1 << 12,
40   WAIT_FOR_WRITE_COMPLETE = 1 << 13
41 };
42
43 }  // namespace
44
45 namespace IPC {
46
47 ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
48   memset(&context.overlapped, 0, sizeof(context.overlapped));
49   context.handler = channel;
50 }
51
52 ChannelWin::State::~State() {
53   COMPILE_ASSERT(!offsetof(ChannelWin::State, context),
54                  starts_with_io_context);
55 }
56
57 ChannelWin::ChannelWin(const IPC::ChannelHandle &channel_handle,
58                        Mode mode, Listener* listener)
59     : ChannelReader(listener),
60       input_state_(this),
61       output_state_(this),
62       pipe_(INVALID_HANDLE_VALUE),
63       peer_pid_(base::kNullProcessId),
64       waiting_connect_(mode & MODE_SERVER_FLAG),
65       processing_incoming_(false),
66       validate_client_(false),
67       writing_(false),
68       debug_flags_(0),
69       client_secret_(0),
70       weak_factory_(this) {
71   CreatePipe(channel_handle, mode);
72 }
73
74 ChannelWin::~ChannelWin() {
75   Close();
76 }
77
78 void ChannelWin::Close() {
79   if (thread_check_.get()) {
80     DCHECK(thread_check_->CalledOnValidThread());
81   }
82   debug_flags_ |= CLOSED;
83
84   if (input_state_.is_pending || output_state_.is_pending)
85     CancelIo(pipe_);
86
87   // Closing the handle at this point prevents us from issuing more requests
88   // form OnIOCompleted().
89   if (pipe_ != INVALID_HANDLE_VALUE) {
90     CloseHandle(pipe_);
91     pipe_ = INVALID_HANDLE_VALUE;
92   }
93
94   if (input_state_.is_pending)
95     debug_flags_ |= WAIT_FOR_READ;
96
97   if (output_state_.is_pending)
98     debug_flags_ |= WAIT_FOR_WRITE;
99
100   // Make sure all IO has completed.
101   base::Time start = base::Time::Now();
102   while (input_state_.is_pending || output_state_.is_pending) {
103     base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
104   }
105
106   while (!output_queue_.empty()) {
107     Message* m = output_queue_.front();
108     output_queue_.pop();
109     delete m;
110   }
111 }
112
113 bool ChannelWin::Send(Message* message) {
114   DCHECK(thread_check_->CalledOnValidThread());
115   DVLOG(2) << "sending message @" << message << " on channel @" << this
116            << " with type " << message->type()
117            << " (" << output_queue_.size() << " in queue)";
118
119 #ifdef IPC_MESSAGE_LOG_ENABLED
120   Logging::GetInstance()->OnSendMessage(message, "");
121 #endif
122
123   message->TraceMessageBegin();
124   output_queue_.push(message);
125   // ensure waiting to write
126   if (!waiting_connect_) {
127     if (!output_state_.is_pending) {
128       if (!ProcessOutgoingMessages(NULL, 0))
129         return false;
130     }
131   }
132
133   return true;
134 }
135
136 base::ProcessId ChannelWin::GetPeerPID() const {
137   return peer_pid_;
138 }
139
140 base::ProcessId ChannelWin::GetSelfPID() const {
141   return GetCurrentProcessId();
142 }
143
144 ChannelHandle ChannelWin::TakePipeHandle() {
145   ChannelHandle handle = ChannelHandle(pipe_);
146   pipe_ = INVALID_HANDLE_VALUE;
147   return handle;
148 }
149
150 // static
151 bool ChannelWin::IsNamedServerInitialized(
152     const std::string& channel_id) {
153   if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1))
154     return true;
155   // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another
156   // connection.
157   return GetLastError() == ERROR_SEM_TIMEOUT;
158 }
159
160 ChannelWin::ReadState ChannelWin::ReadData(
161     char* buffer,
162     int buffer_len,
163     int* /* bytes_read */) {
164   if (INVALID_HANDLE_VALUE == pipe_)
165     return READ_FAILED;
166
167   debug_flags_ |= READ_MSG;
168   DWORD bytes_read = 0;
169   BOOL ok = ReadFile(pipe_, buffer, buffer_len,
170                      &bytes_read, &input_state_.context.overlapped);
171   if (!ok) {
172     DWORD err = GetLastError();
173     if (err == ERROR_IO_PENDING) {
174       input_state_.is_pending = true;
175       return READ_PENDING;
176     }
177     LOG(ERROR) << "pipe error: " << err;
178     return READ_FAILED;
179   }
180
181   // We could return READ_SUCCEEDED here. But the way that this code is
182   // structured we instead go back to the message loop. Our completion port
183   // will be signalled even in the "synchronously completed" state.
184   //
185   // This allows us to potentially process some outgoing messages and
186   // interleave other work on this thread when we're getting hammered with
187   // input messages. Potentially, this could be tuned to be more efficient
188   // with some testing.
189   input_state_.is_pending = true;
190   return READ_PENDING;
191 }
192
193 bool ChannelWin::WillDispatchInputMessage(Message* msg) {
194   // Make sure we get a hello when client validation is required.
195   if (validate_client_)
196     return IsHelloMessage(*msg);
197   return true;
198 }
199
200 void ChannelWin::HandleInternalMessage(const Message& msg) {
201   DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE));
202   // The hello message contains one parameter containing the PID.
203   PickleIterator it(msg);
204   int32 claimed_pid;
205   bool failed = !it.ReadInt(&claimed_pid);
206
207   if (!failed && validate_client_) {
208     int32 secret;
209     failed = it.ReadInt(&secret) ? (secret != client_secret_) : true;
210   }
211
212   if (failed) {
213     NOTREACHED();
214     Close();
215     listener()->OnChannelError();
216     return;
217   }
218
219   peer_pid_ = claimed_pid;
220   // Validation completed.
221   validate_client_ = false;
222   listener()->OnChannelConnected(claimed_pid);
223 }
224
225 bool ChannelWin::DidEmptyInputBuffers() {
226   // We don't need to do anything here.
227   return true;
228 }
229
230 // static
231 const base::string16 ChannelWin::PipeName(
232     const std::string& channel_id, int32* secret) {
233   std::string name("\\\\.\\pipe\\chrome.");
234
235   // Prevent the shared secret from ending up in the pipe name.
236   size_t index = channel_id.find_first_of('\\');
237   if (index != std::string::npos) {
238     if (secret)  // Retrieve the secret if asked for.
239       base::StringToInt(channel_id.substr(index + 1), secret);
240     return base::ASCIIToWide(name.append(channel_id.substr(0, index - 1)));
241   }
242
243   // This case is here to support predictable named pipes in tests.
244   if (secret)
245     *secret = 0;
246   return base::ASCIIToWide(name.append(channel_id));
247 }
248
249 bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle,
250                                       Mode mode) {
251   DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_);
252   base::string16 pipe_name;
253   // If we already have a valid pipe for channel just copy it.
254   if (channel_handle.pipe.handle) {
255     DCHECK(channel_handle.name.empty());
256     pipe_name = L"Not Available";  // Just used for LOG
257     // Check that the given pipe confirms to the specified mode.  We can
258     // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the
259     // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0.
260     DWORD flags = 0;
261     GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL);
262     DCHECK(!(flags & PIPE_TYPE_MESSAGE));
263     if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) ||
264         ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) {
265       LOG(WARNING) << "Inconsistent open mode. Mode :" << mode;
266       return false;
267     }
268     if (!DuplicateHandle(GetCurrentProcess(),
269                          channel_handle.pipe.handle,
270                          GetCurrentProcess(),
271                          &pipe_,
272                          0,
273                          FALSE,
274                          DUPLICATE_SAME_ACCESS)) {
275       LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError();
276       return false;
277     }
278   } else if (mode & MODE_SERVER_FLAG) {
279     DCHECK(!channel_handle.pipe.handle);
280     const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
281                             FILE_FLAG_FIRST_PIPE_INSTANCE;
282     pipe_name = PipeName(channel_handle.name, &client_secret_);
283     validate_client_ = !!client_secret_;
284     pipe_ = CreateNamedPipeW(pipe_name.c_str(),
285                              open_mode,
286                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
287                              1,
288                              Channel::kReadBufferSize,
289                              Channel::kReadBufferSize,
290                              5000,
291                              NULL);
292   } else if (mode & MODE_CLIENT_FLAG) {
293     DCHECK(!channel_handle.pipe.handle);
294     pipe_name = PipeName(channel_handle.name, &client_secret_);
295     pipe_ = CreateFileW(pipe_name.c_str(),
296                         GENERIC_READ | GENERIC_WRITE,
297                         0,
298                         NULL,
299                         OPEN_EXISTING,
300                         SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
301                             FILE_FLAG_OVERLAPPED,
302                         NULL);
303   } else {
304     NOTREACHED();
305   }
306
307   if (pipe_ == INVALID_HANDLE_VALUE) {
308     // If this process is being closed, the pipe may be gone already.
309     PLOG(WARNING) << "Unable to create pipe \"" << pipe_name << "\" in "
310                   << (mode & MODE_SERVER_FLAG ? "server" : "client") << " mode";
311     return false;
312   }
313
314   // Create the Hello message to be sent when Connect is called
315   scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
316                                     HELLO_MESSAGE_TYPE,
317                                     IPC::Message::PRIORITY_NORMAL));
318
319   // Don't send the secret to the untrusted process, and don't send a secret
320   // if the value is zero (for IPC backwards compatability).
321   int32 secret = validate_client_ ? 0 : client_secret_;
322   if (!m->WriteInt(GetCurrentProcessId()) ||
323       (secret && !m->WriteUInt32(secret))) {
324     CloseHandle(pipe_);
325     pipe_ = INVALID_HANDLE_VALUE;
326     return false;
327   }
328
329   debug_flags_ |= INIT_DONE;
330
331   output_queue_.push(m.release());
332   return true;
333 }
334
335 bool ChannelWin::Connect() {
336   DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
337
338   if (!thread_check_.get())
339     thread_check_.reset(new base::ThreadChecker());
340
341   if (pipe_ == INVALID_HANDLE_VALUE)
342     return false;
343
344   base::MessageLoopForIO::current()->RegisterIOHandler(pipe_, this);
345
346   // Check to see if there is a client connected to our pipe...
347   if (waiting_connect_)
348     ProcessConnection();
349
350   if (!input_state_.is_pending) {
351     // Complete setup asynchronously. By not setting input_state_.is_pending
352     // to true, we indicate to OnIOCompleted that this is the special
353     // initialization signal.
354     base::MessageLoopForIO::current()->PostTask(
355         FROM_HERE,
356         base::Bind(&ChannelWin::OnIOCompleted,
357                    weak_factory_.GetWeakPtr(),
358                    &input_state_.context,
359                    0,
360                    0));
361   }
362
363   if (!waiting_connect_)
364     ProcessOutgoingMessages(NULL, 0);
365   return true;
366 }
367
368 bool ChannelWin::ProcessConnection() {
369   DCHECK(thread_check_->CalledOnValidThread());
370   if (input_state_.is_pending)
371     input_state_.is_pending = false;
372
373   // Do we have a client connected to our pipe?
374   if (INVALID_HANDLE_VALUE == pipe_)
375     return false;
376
377   BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped);
378   debug_flags_ |= CALLED_CONNECT;
379
380   DWORD err = GetLastError();
381   if (ok) {
382     // Uhm, the API documentation says that this function should never
383     // return success when used in overlapped mode.
384     NOTREACHED();
385     return false;
386   }
387
388   switch (err) {
389   case ERROR_IO_PENDING:
390     input_state_.is_pending = true;
391     debug_flags_ |= PENDING_CONNECT;
392     break;
393   case ERROR_PIPE_CONNECTED:
394     debug_flags_ |= PIPE_CONNECTED;
395     waiting_connect_ = false;
396     break;
397   case ERROR_NO_DATA:
398     // The pipe is being closed.
399     return false;
400   default:
401     NOTREACHED();
402     return false;
403   }
404
405   return true;
406 }
407
408 bool ChannelWin::ProcessOutgoingMessages(
409     base::MessageLoopForIO::IOContext* context,
410     DWORD bytes_written) {
411   DCHECK(!waiting_connect_);  // Why are we trying to send messages if there's
412                               // no connection?
413   DCHECK(thread_check_->CalledOnValidThread());
414
415   if (output_state_.is_pending) {
416     DCHECK(context);
417     output_state_.is_pending = false;
418     if (!context || bytes_written == 0) {
419       DWORD err = GetLastError();
420       LOG(ERROR) << "pipe error: " << err;
421       return false;
422     }
423     // Message was sent.
424     CHECK(!output_queue_.empty());
425     Message* m = output_queue_.front();
426     output_queue_.pop();
427     delete m;
428   }
429
430   if (output_queue_.empty())
431     return true;
432
433   if (INVALID_HANDLE_VALUE == pipe_)
434     return false;
435
436   // Write to pipe...
437   Message* m = output_queue_.front();
438   DCHECK(m->size() <= INT_MAX);
439   debug_flags_ |= WRITE_MSG;
440   CHECK(!writing_);
441   writing_ = true;
442   BOOL ok = WriteFile(pipe_,
443                       m->data(),
444                       static_cast<int>(m->size()),
445                       &bytes_written,
446                       &output_state_.context.overlapped);
447   if (!ok) {
448     DWORD err = GetLastError();
449     if (err == ERROR_IO_PENDING) {
450       output_state_.is_pending = true;
451
452       DVLOG(2) << "sent pending message @" << m << " on channel @" << this
453                << " with type " << m->type();
454
455       return true;
456     }
457     writing_ = false;
458     LOG(ERROR) << "pipe error: " << err;
459     return false;
460   }
461
462   DVLOG(2) << "sent message @" << m << " on channel @" << this
463            << " with type " << m->type();
464
465   output_state_.is_pending = true;
466   return true;
467 }
468
469 void ChannelWin::OnIOCompleted(
470     base::MessageLoopForIO::IOContext* context,
471     DWORD bytes_transfered,
472     DWORD error) {
473   bool ok = true;
474   DCHECK(thread_check_->CalledOnValidThread());
475   if (context == &input_state_.context) {
476     if (waiting_connect_) {
477       debug_flags_ |= CONNECT_COMPLETED;
478       if (!ProcessConnection())
479         return;
480       // We may have some messages queued up to send...
481       if (!output_queue_.empty() && !output_state_.is_pending)
482         ProcessOutgoingMessages(NULL, 0);
483       if (input_state_.is_pending)
484         return;
485       // else, fall-through and look for incoming messages...
486     }
487
488     // We don't support recursion through OnMessageReceived yet!
489     DCHECK(!processing_incoming_);
490     base::AutoReset<bool> auto_reset_processing_incoming(
491         &processing_incoming_, true);
492
493     // Process the new data.
494     if (input_state_.is_pending) {
495       // This is the normal case for everything except the initialization step.
496       debug_flags_ |= READ_COMPLETED;
497       if (debug_flags_ & WAIT_FOR_READ) {
498         CHECK(!(debug_flags_ & WAIT_FOR_READ_COMPLETE));
499         debug_flags_ |= WAIT_FOR_READ_COMPLETE;
500       }
501       input_state_.is_pending = false;
502       if (!bytes_transfered)
503         ok = false;
504       else if (pipe_ != INVALID_HANDLE_VALUE)
505         ok = AsyncReadComplete(bytes_transfered);
506     } else {
507       DCHECK(!bytes_transfered);
508     }
509
510     // Request more data.
511     if (ok)
512       ok = ProcessIncomingMessages();
513   } else {
514     DCHECK(context == &output_state_.context);
515     CHECK(writing_);
516     CHECK(output_state_.is_pending);
517     writing_ = false;
518     debug_flags_ |= WRITE_COMPLETED;
519     if (debug_flags_ & WAIT_FOR_WRITE) {
520       CHECK(!(debug_flags_ & WAIT_FOR_WRITE_COMPLETE));
521       debug_flags_ |= WAIT_FOR_WRITE_COMPLETE;
522     }
523     ok = ProcessOutgoingMessages(context, bytes_transfered);
524   }
525   if (!ok && INVALID_HANDLE_VALUE != pipe_) {
526     // We don't want to re-enter Close().
527     Close();
528     listener()->OnChannelError();
529   }
530 }
531
532 //------------------------------------------------------------------------------
533 // Channel's methods
534
535 // static
536 scoped_ptr<Channel> Channel::Create(
537     const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener) {
538   return scoped_ptr<Channel>(
539       new ChannelWin(channel_handle, mode, listener));
540 }
541
542 // static
543 bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
544   return ChannelWin::IsNamedServerInitialized(channel_id);
545 }
546
547 // static
548 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) {
549   // Windows pipes can be enumerated by low-privileged processes. So, we
550   // append a strong random value after the \ character. This value is not
551   // included in the pipe name, but sent as part of the client hello, to
552   // hijacking the pipe name to spoof the client.
553
554   std::string id = prefix;
555   if (!id.empty())
556     id.append(".");
557
558   int secret;
559   do {  // Guarantee we get a non-zero value.
560     secret = base::RandInt(0, std::numeric_limits<int>::max());
561   } while (secret == 0);
562
563   id.append(GenerateUniqueRandomChannelID());
564   return id.append(base::StringPrintf("\\%d", secret));
565 }
566
567 }  // namespace IPC