1 // Copyright 2017 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 #ifndef MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
6 #define MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
7 
8 #include <string>
9 
10 #include "base/callback.h"
11 #include "base/macros.h"
12 #include "base/process/process_handle.h"
13 #include "mojo/edk/embedder/connection_params.h"
14 #include "mojo/edk/embedder/scoped_platform_handle.h"
15 #include "mojo/edk/system/system_impl_export.h"
16 #include "mojo/public/cpp/system/message_pipe.h"
17 
18 namespace mojo {
19 namespace edk {
20 
21 using ProcessErrorCallback = base::Callback<void(const std::string& error)>;
22 
23 // Represents a potential connection to an external process. Use this object
24 // to make other processes reachable from this one via Mojo IPC. Typical usage
25 // might look something like:
26 //
27 //     PendingProcessConnection connection;
28 //
29 //     std::string pipe_token;
30 //     ScopedMessagePipeHandle pipe = connection.CreateMessagePipe(&pipe_token);
31 //
32 //     // New pipes to the process are fully functional and can be used right
33 //     // away, even if the process doesn't exist yet.
34 //     GoDoSomethingInteresting(std::move(pipe));
35 //
36 //     ScopedPlatformChannelPair channel;
37 //
38 //     // Give the pipe token to the child process via command-line.
39 //     child_command_line.AppendSwitchASCII("yer-pipe", pipe_token);
40 //
41 //     // Magic child process launcher which gives one end of the pipe to the
42 //     // new process.
43 //     LaunchProcess(child_command_line, channel.PassClientHandle());
44 //
45 //     // Some time later...
46 //     connection.Connect(new_process, channel.PassServerHandle());
47 //
48 // If at any point during the above process, |connection| is destroyed before
49 // Connect() can be called, |pipe| will imminently behave as if its peer has
50 // been closed.
51 //
52 // Otherwise, if the remote process in this example eventually calls:
53 //
54 //     mojo::edk::SetParentPipeHandle(std::move(client_channel_handle));
55 //
56 //     std::string token = command_line.GetSwitchValueASCII("yer-pipe");
57 //     ScopedMessagePipeHandle pipe = mojo::edk::CreateChildMessagePipe(token);
58 //
59 // it will be connected to this process, and its |pipe| will be connected to
60 // this process's |pipe|.
61 //
62 // If the remote process exits or otherwise closes its client channel handle
63 // before calling CreateChildMessagePipe for a given message pipe token,
64 // this process's end of the corresponding message pipe will imminently behave
65 // as if its peer has been closed.
66 //
67 class MOJO_SYSTEM_IMPL_EXPORT PendingProcessConnection {
68  public:
69   PendingProcessConnection();
70   ~PendingProcessConnection();
71 
72   // Creates a message pipe associated with a new globally unique string value
73   // which will be placed in |*token|.
74   //
75   // The other end of the new pipe is obtainable in the remote process (or in
76   // this process, to facilitate "single-process mode" in some applications) by
77   // passing the new |*token| value to mojo::edk::CreateChildMessagePipe. It's
78   // the caller's responsibility to communicate the value of |*token| to the
79   // remote process by any means available, e.g. a command-line argument on
80   // process launch, or some other out-of-band communication channel for an
81   // existing process.
82   //
83   // NOTES: This may be called any number of times to create multiple message
84   // pipes to the same remote process. This call ALWAYS succeeds, returning
85   // a valid message pipe handle and populating |*token| with a new unique
86   // string value.
87   ScopedMessagePipeHandle CreateMessagePipe(std::string* token);
88 
89   // Connects to the process. This must be called at most once, with the process
90   // handle in |process|.
91   //
92   // |connection_param| contains the platform handle of an OS pipe which can be
93   // used to communicate with the connected process. The other end of that pipe
94   // must ultimately be passed to mojo::edk::SetParentPipeHandle in the remote
95   // process, and getting that end of the pipe into the other process is the
96   // embedder's responsibility.
97   //
98   // If this method is not called by the time the PendingProcessConnection is
99   // destroyed, it's assumed that the process is unavailable (e.g. process
100   // launch failed or the process has otherwise been terminated early), and
101   // any associated resources, such as remote endpoints of messages pipes
102   // created by CreateMessagePipe above) will be cleaned up at that time.
103   void Connect(
104       base::ProcessHandle process,
105       ConnectionParams connection_params,
106       const ProcessErrorCallback& error_callback = ProcessErrorCallback());
107 
108  private:
109   // A GUID representing a potential new process to be connected to this one.
110   const std::string process_token_;
111 
112   // Indicates whether this object has been used to create new message pipes.
113   bool has_message_pipes_ = false;
114 
115   // Indicates whether Connect() has been called yet.
116   bool connected_ = false;
117 
118   DISALLOW_COPY_AND_ASSIGN(PendingProcessConnection);
119 };
120 
121 }  // namespace edk
122 }  // namespace mojo
123 
124 #endif  // MOJO_EDK_EMBEDDER_PENDING_PROCESS_CONNECTION_H_
125