start_host.cc revision 5e3f23d412006dc4db4e659864679f29341e113f
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 <stdio.h> 6#include <termios.h> 7 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 "google_apis/gaia/gaia_urls.h" 14#include "net/url_request/url_fetcher.h" 15#include "net/url_request/url_request_context_getter.h" 16#include "remoting/host/service_urls.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" 20#include "remoting/host/url_request_context.h" 21 22// A simple command-line app that registers and starts a host. 23 24using remoting::HostStarter; 25 26// True if the host was started successfully. 27bool g_started = false; 28 29// The main message loop. 30base::MessageLoop* g_message_loop = NULL; 31 32// Lets us hide the PIN that a user types. 33void SetEcho(bool echo) { 34 termios term; 35 tcgetattr(STDIN_FILENO, &term); 36 if (echo) { 37 term.c_lflag |= ECHO; 38 } else { 39 term.c_lflag &= ~ECHO; 40 } 41 tcsetattr(STDIN_FILENO, TCSANOW, &term); 42} 43 44// Reads a newline-terminated string from stdin. 45std::string ReadString(bool no_echo) { 46 if (no_echo) 47 SetEcho(false); 48 const int kMaxLen = 1024; 49 std::string str(kMaxLen, 0); 50 char* result = fgets(&str[0], kMaxLen, stdin); 51 if (no_echo) { 52 printf("\n"); 53 SetEcho(true); 54 } 55 if (!result) 56 return std::string(); 57 size_t newline_index = str.find('\n'); 58 if (newline_index != std::string::npos) 59 str[newline_index] = '\0'; 60 str.resize(strlen(&str[0])); 61 return str; 62} 63 64// Called when the HostStarter has finished. 65void OnDone(HostStarter::Result result) { 66 if (base::MessageLoop::current() != g_message_loop) { 67 g_message_loop->PostTask(FROM_HERE, base::Bind(&OnDone, result)); 68 return; 69 } 70 switch (result) { 71 case HostStarter::START_COMPLETE: 72 g_started = true; 73 break; 74 case HostStarter::NETWORK_ERROR: 75 fprintf(stderr, "Couldn't start host: network error.\n"); 76 break; 77 case HostStarter::OAUTH_ERROR: 78 fprintf(stderr, "Couldn't start host: OAuth error.\n"); 79 break; 80 case HostStarter::START_ERROR: 81 fprintf(stderr, "Couldn't start host.\n"); 82 break; 83 } 84 85 g_message_loop->QuitNow(); 86} 87 88int main(int argc, char** argv) { 89 // google_apis::GetOAuth2ClientID/Secret need a static CommandLine. 90 CommandLine::Init(argc, argv); 91 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 92 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"); 97 98 if (host_name.empty()) { 99 fprintf(stderr, 100 "Usage: %s --name=<hostname> [--code=<auth-code>] [--pin=<PIN>] " 101 "[--redirect-url=<redirectURL>]\n", 102 argv[0]); 103 return 1; 104 } 105 106 if (host_pin.empty()) { 107 while (true) { 108 fprintf(stdout, "Enter a six-digit PIN: "); 109 fflush(stdout); 110 host_pin = ReadString(true); 111 if (!remoting::IsPinValid(host_pin)) { 112 fprintf(stdout, 113 "Please use a PIN consisting of at least six digits.\n"); 114 fflush(stdout); 115 continue; 116 } 117 std::string host_pin_confirm; 118 fprintf(stdout, "Enter the same PIN again: "); 119 fflush(stdout); 120 host_pin_confirm = ReadString(true); 121 if (host_pin != host_pin_confirm) { 122 fprintf(stdout, "You entered different PINs.\n"); 123 fflush(stdout); 124 continue; 125 } 126 break; 127 } 128 } else { 129 if (!remoting::IsPinValid(host_pin)) { 130 fprintf(stderr, "Please use a PIN consisting of at least six digits.\n"); 131 return 1; 132 } 133 } 134 135 if (auth_code.empty()) { 136 fprintf(stdout, "Enter an authorization code: "); 137 fflush(stdout); 138 auth_code = ReadString(true); 139 } 140 141 // This object instance is required by Chrome code (for example, 142 // FilePath, LazyInstance, MessageLoop). 143 base::AtExitManager exit_manager; 144 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); 151 152 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter( 153 new remoting::URLRequestContextGetter( 154 g_message_loop->message_loop_proxy(), 155 io_thread.message_loop_proxy())); 156 157 if (remoting::ServiceUrls::GetInstance()->ignore_urlfetcher_cert_requests()) { 158 net::URLFetcher::SetIgnoreCertificateRequests(true); 159 } 160 161 // Start the host. 162 scoped_ptr<HostStarter> host_starter(HostStarter::Create( 163 GaiaUrls::GetInstance()->oauth2_token_url(), 164 remoting::ServiceUrls::GetInstance()->directory_hosts_url(), 165 url_request_context_getter.get())); 166 if (redirect_url.empty()) { 167 redirect_url = remoting::GetDefaultOauthRedirectUrl(); 168 } 169 host_starter->StartHost(host_name, host_pin, true, auth_code, redirect_url, 170 base::Bind(&OnDone)); 171 172 // Run the message loop until the StartHost completion callback. 173 base::RunLoop run_loop; 174 run_loop.Run(); 175 176 g_message_loop = NULL; 177 178 // Destroy the HostStarter and URLRequestContextGetter before stopping the 179 // IO thread. 180 host_starter.reset(); 181 url_request_context_getter = NULL; 182 183 io_thread.Stop(); 184 185 return g_started ? 0 : 1; 186} 187