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.
5 // A simple command-line app that registers and starts a host.
9 #include "base/at_exit.h"
10 #include "base/command_line.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/threading/thread.h"
14 #include "net/url_request/url_fetcher.h"
15 #include "net/url_request/url_request_context_getter.h"
16 #include "remoting/base/service_urls.h"
17 #include "remoting/base/url_request_context_getter.h"
18 #include "remoting/host/setup/host_starter.h"
19 #include "remoting/host/setup/oauth_helper.h"
20 #include "remoting/host/setup/pin_validator.h"
24 #endif // !defined(OS_WIN)
26 using remoting::HostStarter
;
28 // True if the host was started successfully.
29 bool g_started
= false;
31 // The main message loop.
32 base::MessageLoop
* g_message_loop
= nullptr;
34 // Lets us hide the PIN that a user types.
35 void SetEcho(bool echo
) {
38 HANDLE console_handle
= GetStdHandle(STD_INPUT_HANDLE
);
39 if (!GetConsoleMode(console_handle
, &mode
)) {
40 LOG(ERROR
) << "GetConsoleMode failed";
43 SetConsoleMode(console_handle
,
44 (mode
& ~ENABLE_ECHO_INPUT
) | (echo
? ENABLE_ECHO_INPUT
: 0));
47 tcgetattr(STDIN_FILENO
, &term
);
51 term
.c_lflag
&= ~ECHO
;
53 tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
54 #endif // !defined(OS_WIN)
57 // Reads a newline-terminated string from stdin.
58 std::string
ReadString(bool no_echo
) {
61 const int kMaxLen
= 1024;
62 std::string
str(kMaxLen
, 0);
63 char* result
= fgets(&str
[0], kMaxLen
, stdin
);
70 size_t newline_index
= str
.find('\n');
71 if (newline_index
!= std::string::npos
)
72 str
[newline_index
] = '\0';
73 str
.resize(strlen(&str
[0]));
77 // Called when the HostStarter has finished.
78 void OnDone(HostStarter::Result result
) {
79 if (base::MessageLoop::current() != g_message_loop
) {
80 g_message_loop
->PostTask(FROM_HERE
, base::Bind(&OnDone
, result
));
84 case HostStarter::START_COMPLETE
:
87 case HostStarter::NETWORK_ERROR
:
88 fprintf(stderr
, "Couldn't start host: network error.\n");
90 case HostStarter::OAUTH_ERROR
:
91 fprintf(stderr
, "Couldn't start host: OAuth error.\n");
93 case HostStarter::START_ERROR
:
94 fprintf(stderr
, "Couldn't start host.\n");
98 g_message_loop
->QuitNow();
101 int main(int argc
, char** argv
) {
102 // google_apis::GetOAuth2ClientID/Secret need a static CommandLine.
103 base::CommandLine::Init(argc
, argv
);
104 const base::CommandLine
* command_line
=
105 base::CommandLine::ForCurrentProcess();
107 std::string host_name
= command_line
->GetSwitchValueASCII("name");
108 std::string host_pin
= command_line
->GetSwitchValueASCII("pin");
109 std::string auth_code
= command_line
->GetSwitchValueASCII("code");
110 std::string redirect_url
= command_line
->GetSwitchValueASCII("redirect-url");
112 if (host_name
.empty()) {
114 "Usage: %s --name=<hostname> [--code=<auth-code>] [--pin=<PIN>] "
115 "[--redirect-url=<redirectURL>]\n",
120 if (host_pin
.empty()) {
122 fprintf(stdout
, "Enter a six-digit PIN: ");
124 host_pin
= ReadString(true);
125 if (!remoting::IsPinValid(host_pin
)) {
127 "Please use a PIN consisting of at least six digits.\n");
131 std::string host_pin_confirm
;
132 fprintf(stdout
, "Enter the same PIN again: ");
134 host_pin_confirm
= ReadString(true);
135 if (host_pin
!= host_pin_confirm
) {
136 fprintf(stdout
, "You entered different PINs.\n");
143 if (!remoting::IsPinValid(host_pin
)) {
144 fprintf(stderr
, "Please use a PIN consisting of at least six digits.\n");
149 if (auth_code
.empty()) {
150 fprintf(stdout
, "Enter an authorization code: ");
152 auth_code
= ReadString(true);
155 // This object instance is required by Chrome code (for example,
156 // FilePath, LazyInstance, MessageLoop).
157 base::AtExitManager exit_manager
;
159 // Provide message loops and threads for the URLRequestContextGetter.
160 base::MessageLoop message_loop
;
161 g_message_loop
= &message_loop
;
162 base::Thread::Options
io_thread_options(base::MessageLoop::TYPE_IO
, 0);
163 base::Thread
io_thread("IO thread");
164 io_thread
.StartWithOptions(io_thread_options
);
165 base::Thread
file_thread("file thread");
166 file_thread
.StartWithOptions(io_thread_options
);
168 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter(
169 new remoting::URLRequestContextGetter(io_thread
.task_runner(),
170 file_thread
.task_runner()));
172 net::URLFetcher::SetIgnoreCertificateRequests(true);
175 scoped_ptr
<HostStarter
> host_starter(HostStarter::Create(
176 remoting::ServiceUrls::GetInstance()->directory_hosts_url(),
177 url_request_context_getter
.get()));
178 if (redirect_url
.empty()) {
179 redirect_url
= remoting::GetDefaultOauthRedirectUrl();
181 host_starter
->StartHost(host_name
, host_pin
, true, auth_code
, redirect_url
,
182 base::Bind(&OnDone
));
184 // Run the message loop until the StartHost completion callback.
185 base::RunLoop run_loop
;
188 g_message_loop
= nullptr;
190 // Destroy the HostStarter and URLRequestContextGetter before stopping the
192 host_starter
.reset();
193 url_request_context_getter
= nullptr;
197 return g_started
? 0 : 1;