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/logging.h"
17 #include "remoting/base/service_urls.h"
18 #include "remoting/base/url_request_context_getter.h"
19 #include "remoting/host/setup/host_starter.h"
20 #include "remoting/host/setup/oauth_helper.h"
21 #include "remoting/host/setup/pin_validator.h"
25 #endif // !defined(OS_WIN)
27 using remoting::HostStarter
;
29 // True if the host was started successfully.
30 bool g_started
= false;
32 // The main message loop.
33 base::MessageLoop
* g_message_loop
= nullptr;
35 // Lets us hide the PIN that a user types.
36 void SetEcho(bool echo
) {
39 HANDLE console_handle
= GetStdHandle(STD_INPUT_HANDLE
);
40 if (!GetConsoleMode(console_handle
, &mode
)) {
41 LOG(ERROR
) << "GetConsoleMode failed";
44 SetConsoleMode(console_handle
,
45 (mode
& ~ENABLE_ECHO_INPUT
) | (echo
? ENABLE_ECHO_INPUT
: 0));
48 tcgetattr(STDIN_FILENO
, &term
);
52 term
.c_lflag
&= ~ECHO
;
54 tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
55 #endif // !defined(OS_WIN)
58 // Reads a newline-terminated string from stdin.
59 std::string
ReadString(bool no_echo
) {
62 const int kMaxLen
= 1024;
63 std::string
str(kMaxLen
, 0);
64 char* result
= fgets(&str
[0], kMaxLen
, stdin
);
71 size_t newline_index
= str
.find('\n');
72 if (newline_index
!= std::string::npos
)
73 str
[newline_index
] = '\0';
74 str
.resize(strlen(&str
[0]));
78 // Called when the HostStarter has finished.
79 void OnDone(HostStarter::Result result
) {
80 if (base::MessageLoop::current() != g_message_loop
) {
81 g_message_loop
->PostTask(FROM_HERE
, base::Bind(&OnDone
, result
));
85 case HostStarter::START_COMPLETE
:
88 case HostStarter::NETWORK_ERROR
:
89 fprintf(stderr
, "Couldn't start host: network error.\n");
91 case HostStarter::OAUTH_ERROR
:
92 fprintf(stderr
, "Couldn't start host: OAuth error.\n");
94 case HostStarter::START_ERROR
:
95 fprintf(stderr
, "Couldn't start host.\n");
99 g_message_loop
->QuitNow();
102 int main(int argc
, char** argv
) {
103 // google_apis::GetOAuth2ClientID/Secret need a static CommandLine.
104 base::CommandLine::Init(argc
, argv
);
105 const base::CommandLine
* command_line
=
106 base::CommandLine::ForCurrentProcess();
108 logging::LoggingSettings settings
;
109 logging::InitLogging(settings
);
111 std::string host_name
= command_line
->GetSwitchValueASCII("name");
112 std::string host_pin
= command_line
->GetSwitchValueASCII("pin");
113 std::string auth_code
= command_line
->GetSwitchValueASCII("code");
114 std::string redirect_url
= command_line
->GetSwitchValueASCII("redirect-url");
116 if (host_name
.empty()) {
118 "Usage: %s --name=<hostname> [--code=<auth-code>] [--pin=<PIN>] "
119 "[--redirect-url=<redirectURL>]\n",
124 if (host_pin
.empty()) {
126 fprintf(stdout
, "Enter a six-digit PIN: ");
128 host_pin
= ReadString(true);
129 if (!remoting::IsPinValid(host_pin
)) {
131 "Please use a PIN consisting of at least six digits.\n");
135 std::string host_pin_confirm
;
136 fprintf(stdout
, "Enter the same PIN again: ");
138 host_pin_confirm
= ReadString(true);
139 if (host_pin
!= host_pin_confirm
) {
140 fprintf(stdout
, "You entered different PINs.\n");
147 if (!remoting::IsPinValid(host_pin
)) {
148 fprintf(stderr
, "Please use a PIN consisting of at least six digits.\n");
153 if (auth_code
.empty()) {
154 fprintf(stdout
, "Enter an authorization code: ");
156 auth_code
= ReadString(true);
159 // This object instance is required by Chrome code (for example,
160 // FilePath, LazyInstance, MessageLoop).
161 base::AtExitManager exit_manager
;
163 // Provide message loops and threads for the URLRequestContextGetter.
164 base::MessageLoop message_loop
;
165 g_message_loop
= &message_loop
;
166 base::Thread::Options
io_thread_options(base::MessageLoop::TYPE_IO
, 0);
167 base::Thread
io_thread("IO thread");
168 io_thread
.StartWithOptions(io_thread_options
);
169 base::Thread
file_thread("file thread");
170 file_thread
.StartWithOptions(io_thread_options
);
172 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter(
173 new remoting::URLRequestContextGetter(io_thread
.task_runner(),
174 file_thread
.task_runner()));
176 net::URLFetcher::SetIgnoreCertificateRequests(true);
179 scoped_ptr
<HostStarter
> host_starter(HostStarter::Create(
180 remoting::ServiceUrls::GetInstance()->directory_hosts_url(),
181 url_request_context_getter
.get()));
182 if (redirect_url
.empty()) {
183 redirect_url
= remoting::GetDefaultOauthRedirectUrl();
185 host_starter
->StartHost(host_name
, host_pin
, true, auth_code
, redirect_url
,
186 base::Bind(&OnDone
));
188 // Run the message loop until the StartHost completion callback.
189 base::RunLoop run_loop
;
192 g_message_loop
= nullptr;
194 // Destroy the HostStarter and URLRequestContextGetter before stopping the
196 host_starter
.reset();
197 url_request_context_getter
= nullptr;
201 return g_started
? 0 : 1;