start_host.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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 "net/url_request/url_fetcher.h" 14#include "net/url_request/url_request_context_getter.h" 15#include "remoting/base/url_request_context.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 21// A simple command-line app that registers and starts a host. 22 23using remoting::HostStarter; 24 25// True if the host was started successfully. 26bool g_started = false; 27 28// The main message loop. 29base::MessageLoop* g_message_loop = NULL; 30 31// Lets us hide the PIN that a user types. 32void SetEcho(bool echo) { 33 termios term; 34 tcgetattr(STDIN_FILENO, &term); 35 if (echo) { 36 term.c_lflag |= ECHO; 37 } else { 38 term.c_lflag &= ~ECHO; 39 } 40 tcsetattr(STDIN_FILENO, TCSANOW, &term); 41} 42 43// Reads a newline-terminated string from stdin. 44std::string ReadString(bool no_echo) { 45 if (no_echo) 46 SetEcho(false); 47 const int kMaxLen = 1024; 48 std::string str(kMaxLen, 0); 49 char* result = fgets(&str[0], kMaxLen, stdin); 50 if (no_echo) { 51 printf("\n"); 52 SetEcho(true); 53 } 54 if (!result) 55 return std::string(); 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])); 60 return str; 61} 62 63// Called when the HostStarter has finished. 64void OnDone(HostStarter::Result result) { 65 if (base::MessageLoop::current() != g_message_loop) { 66 g_message_loop->PostTask(FROM_HERE, base::Bind(&OnDone, result)); 67 return; 68 } 69 switch (result) { 70 case HostStarter::START_COMPLETE: 71 g_started = true; 72 break; 73 case HostStarter::NETWORK_ERROR: 74 fprintf(stderr, "Couldn't start host: network error.\n"); 75 break; 76 case HostStarter::OAUTH_ERROR: 77 fprintf(stderr, "Couldn't start host: OAuth error.\n"); 78 break; 79 case HostStarter::START_ERROR: 80 fprintf(stderr, "Couldn't start host.\n"); 81 break; 82 } 83 84 g_message_loop->QuitNow(); 85} 86 87int 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(); 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(io_thread.message_loop_proxy())); 154 155 net::URLFetcher::SetIgnoreCertificateRequests(true); 156 157 // Start the host. 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(); 163 } 164 host_starter->StartHost(host_name, host_pin, true, auth_code, redirect_url, 165 base::Bind(&OnDone)); 166 167 // Run the message loop until the StartHost completion callback. 168 base::RunLoop run_loop; 169 run_loop.Run(); 170 171 g_message_loop = NULL; 172 173 // Destroy the HostStarter and URLRequestContextGetter before stopping the 174 // IO thread. 175 host_starter.reset(); 176 url_request_context_getter = NULL; 177 178 io_thread.Stop(); 179 180 return g_started ? 0 : 1; 181} 182