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.
8 #include "base/at_exit.h"
9 #include "base/command_line.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/threading/thread.h"
13 #include "net/url_request/url_fetcher.h"
14 #include "net/url_request/url_request_context_getter.h"
15 #include "remoting/base/service_urls.h"
16 #include "remoting/base/url_request_context_getter.h"
17 #include "remoting/host/setup/host_starter.h"
18 #include "remoting/host/setup/oauth_helper.h"
19 #include "remoting/host/setup/pin_validator.h"
21 // A simple command-line app that registers and starts a host.
23 using remoting::HostStarter
;
25 // True if the host was started successfully.
26 bool g_started
= false;
28 // The main message loop.
29 base::MessageLoop
* g_message_loop
= NULL
;
31 // Lets us hide the PIN that a user types.
32 void SetEcho(bool echo
) {
34 tcgetattr(STDIN_FILENO
, &term
);
38 term
.c_lflag
&= ~ECHO
;
40 tcsetattr(STDIN_FILENO
, TCSANOW
, &term
);
43 // Reads a newline-terminated string from stdin.
44 std::string
ReadString(bool no_echo
) {
47 const int kMaxLen
= 1024;
48 std::string
str(kMaxLen
, 0);
49 char* result
= fgets(&str
[0], kMaxLen
, stdin
);
56 size_t newline_index
= str
.find('\n');
57 if (newline_index
!= std::string::npos
)
58 str
[newline_index
] = '\0';
59 str
.resize(strlen(&str
[0]));
63 // Called when the HostStarter has finished.
64 void OnDone(HostStarter::Result result
) {
65 if (base::MessageLoop::current() != g_message_loop
) {
66 g_message_loop
->PostTask(FROM_HERE
, base::Bind(&OnDone
, result
));
70 case HostStarter::START_COMPLETE
:
73 case HostStarter::NETWORK_ERROR
:
74 fprintf(stderr
, "Couldn't start host: network error.\n");
76 case HostStarter::OAUTH_ERROR
:
77 fprintf(stderr
, "Couldn't start host: OAuth error.\n");
79 case HostStarter::START_ERROR
:
80 fprintf(stderr
, "Couldn't start host.\n");
84 g_message_loop
->QuitNow();
87 int main(int argc
, char** argv
) {
88 // google_apis::GetOAuth2ClientID/Secret need a static CommandLine.
89 base::CommandLine::Init(argc
, argv
);
90 const base::CommandLine
* command_line
=
91 base::CommandLine::ForCurrentProcess();
93 std::string host_name
= command_line
->GetSwitchValueASCII("name");
94 std::string host_pin
= command_line
->GetSwitchValueASCII("pin");
95 std::string auth_code
= command_line
->GetSwitchValueASCII("code");
96 std::string redirect_url
= command_line
->GetSwitchValueASCII("redirect-url");
98 if (host_name
.empty()) {
100 "Usage: %s --name=<hostname> [--code=<auth-code>] [--pin=<PIN>] "
101 "[--redirect-url=<redirectURL>]\n",
106 if (host_pin
.empty()) {
108 fprintf(stdout
, "Enter a six-digit PIN: ");
110 host_pin
= ReadString(true);
111 if (!remoting::IsPinValid(host_pin
)) {
113 "Please use a PIN consisting of at least six digits.\n");
117 std::string host_pin_confirm
;
118 fprintf(stdout
, "Enter the same PIN again: ");
120 host_pin_confirm
= ReadString(true);
121 if (host_pin
!= host_pin_confirm
) {
122 fprintf(stdout
, "You entered different PINs.\n");
129 if (!remoting::IsPinValid(host_pin
)) {
130 fprintf(stderr
, "Please use a PIN consisting of at least six digits.\n");
135 if (auth_code
.empty()) {
136 fprintf(stdout
, "Enter an authorization code: ");
138 auth_code
= ReadString(true);
141 // This object instance is required by Chrome code (for example,
142 // FilePath, LazyInstance, MessageLoop).
143 base::AtExitManager exit_manager
;
145 // Provide message loops and threads for the URLRequestContextGetter.
146 base::MessageLoop message_loop
;
147 g_message_loop
= &message_loop
;
148 base::Thread
io_thread("IO thread");
149 base::Thread::Options
io_thread_options(base::MessageLoop::TYPE_IO
, 0);
150 io_thread
.StartWithOptions(io_thread_options
);
152 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter(
153 new remoting::URLRequestContextGetter(io_thread
.message_loop_proxy()));
155 net::URLFetcher::SetIgnoreCertificateRequests(true);
158 scoped_ptr
<HostStarter
> host_starter(HostStarter::Create(
159 remoting::ServiceUrls::GetInstance()->directory_hosts_url(),
160 url_request_context_getter
.get()));
161 if (redirect_url
.empty()) {
162 redirect_url
= remoting::GetDefaultOauthRedirectUrl();
164 host_starter
->StartHost(host_name
, host_pin
, true, auth_code
, redirect_url
,
165 base::Bind(&OnDone
));
167 // Run the message loop until the StartHost completion callback.
168 base::RunLoop run_loop
;
171 g_message_loop
= NULL
;
173 // Destroy the HostStarter and URLRequestContextGetter before stopping the
175 host_starter
.reset();
176 url_request_context_getter
= NULL
;
180 return g_started
? 0 : 1;