Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cloud_print/gcp20/prototype/printer.h" | 5 #include "cloud_print/gcp20/prototype/printer.h" |
| 6 | 6 |
| 7 #if defined(OS_WIN) | |
| 8 #include <conio.h> | |
| 9 #else | |
| 10 #include <stdio.h> | |
| 11 #include <sys/types.h> | |
| 12 #include <sys/time.h> | |
| 13 #include <termios.h> | |
| 14 #include <unistd.h> | |
| 15 #endif // !defined(OS_WIN) | |
| 16 #include <iostream> | |
| 7 #include <string> | 17 #include <string> |
| 8 #include <vector> | 18 #include <vector> |
| 9 | 19 |
| 10 #include "base/command_line.h" | 20 #include "base/command_line.h" |
| 11 #include "base/file_util.h" | 21 #include "base/file_util.h" |
| 12 #include "base/guid.h" | 22 #include "base/guid.h" |
| 13 #include "base/json/json_reader.h" | 23 #include "base/json/json_reader.h" |
| 14 #include "base/json/json_writer.h" | 24 #include "base/json/json_writer.h" |
| 15 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
| 16 #include "cloud_print/gcp20/prototype/command_line_reader.h" | 26 #include "cloud_print/gcp20/prototype/command_line_reader.h" |
| 17 #include "cloud_print/gcp20/prototype/service_parameters.h" | 27 #include "cloud_print/gcp20/prototype/service_parameters.h" |
| 18 #include "net/base/net_util.h" | 28 #include "net/base/net_util.h" |
| 19 #include "net/base/url_util.h" | 29 #include "net/base/url_util.h" |
| 20 | 30 |
| 21 const char* kPrinterStatePath = "printer_state.json"; | 31 const char* kPrinterStatePath = "printer_state.json"; |
| 22 | 32 |
| 23 namespace { | 33 namespace { |
| 24 | 34 |
| 25 const char* kServiceType = "_privet._tcp.local"; | 35 const char* kServiceType = "_privet._tcp.local"; |
| 26 const char* kServiceNamePrefix = "first_gcp20_device"; | 36 const char* kServiceNamePrefix = "first_gcp20_device"; |
|
Vitaly Buka (NO REVIEWS)
2013/07/17 06:59:00
Just noticed, please replace all such consts with
maksymb
2013/07/17 18:24:50
Done.
| |
| 27 const char* kServiceDomainName = "my-privet-device.local"; | 37 const char* kServiceDomainName = "my-privet-device.local"; |
| 28 | 38 |
| 29 const char* kPrinterName = "Google GCP2.0 Prototype"; | 39 const char* kPrinterName = "Google GCP2.0 Prototype"; |
| 30 const char* kPrinterDescription = "Printer emulator"; | 40 const char* kPrinterDescription = "Printer emulator"; |
| 31 | 41 |
| 42 const char* kUserConfirmationTitle = "Confirm registration: type 'y' if you " | |
| 43 "agree and any other for otherwise."; | |
| 44 const uint kUserConfirmationTimeout = 10; // in seconds | |
| 45 | |
| 32 const char* kCdd = | 46 const char* kCdd = |
| 33 "{\n" | 47 "{\n" |
| 34 " 'version': '1.0',\n" | 48 " 'version': '1.0',\n" |
| 35 " 'printer': {\n" | 49 " 'printer': {\n" |
| 36 " 'vendor_capability': [\n" | 50 " 'vendor_capability': [\n" |
| 37 " {\n" | 51 " {\n" |
| 38 " 'id': 'psk:MediaType',\n" | 52 " 'id': 'psk:MediaType',\n" |
| 39 " 'display_name': 'Media Type',\n" | 53 " 'display_name': 'Media Type',\n" |
| 40 " 'type': 'SELECT',\n" | 54 " 'type': 'SELECT',\n" |
| 41 " 'select_cap': {\n" | 55 " 'select_cap': {\n" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 76 if (iter->address.size() == expected_address_size && | 90 if (iter->address.size() == expected_address_size && |
| 77 (interface_name.empty() || interface_name == iter->name)) { | 91 (interface_name.empty() || interface_name == iter->name)) { |
| 78 LOG(INFO) << net::IPAddressToString(iter->address); | 92 LOG(INFO) << net::IPAddressToString(iter->address); |
| 79 return iter->address; | 93 return iter->address; |
| 80 } | 94 } |
| 81 } | 95 } |
| 82 | 96 |
| 83 return net::IPAddressNumber(); | 97 return net::IPAddressNumber(); |
| 84 } | 98 } |
| 85 | 99 |
| 100 #if !defined(OS_WIN) | |
|
maksymb
2013/07/17 01:28:20
I don't like to see all this stuff here, in this f
Vitaly Buka (NO REVIEWS)
2013/07/17 06:59:00
sure, you can put this in some file with _posix.cc
maksymb
2013/07/17 18:24:50
Done.
| |
| 101 | |
| 102 // Method for disabling buffered IO. | |
| 103 // |true| - disable, |false| - restore previous settings. | |
| 104 void SetTemporaryTermiosSettings(bool temporary) { | |
| 105 static termios oldt, newt; | |
| 106 | |
| 107 if (temporary) { | |
| 108 tcgetattr(STDIN_FILENO, &oldt); | |
| 109 newt = oldt; | |
| 110 newt.c_lflag &= ~ICANON; // Disable buffered IO. | |
| 111 tcsetattr(STDIN_FILENO, TCSANOW, &newt); | |
| 112 } else { | |
| 113 tcsetattr(STDIN_FILENO, TCSANOW, &oldt); // Restore default settings. | |
| 114 } | |
| 115 } | |
| 116 | |
| 117 // Analog from conio.h | |
| 118 int kbhit() { | |
| 119 SetTemporaryTermiosSettings(true); | |
| 120 | |
| 121 timeval tv; | |
| 122 fd_set rdfs; | |
| 123 | |
| 124 tv.tv_sec = 0; | |
| 125 tv.tv_usec = 0; | |
| 126 | |
| 127 FD_ZERO(&rdfs); | |
| 128 FD_SET(STDIN_FILENO, &rdfs); | |
| 129 select(STDIN_FILENO + 1, &rdfs, NULL, NULL, &tv); | |
| 130 SetTemporaryTermiosSettings(false); | |
| 131 | |
| 132 return FD_ISSET(STDIN_FILENO, &rdfs); | |
| 133 } | |
| 134 | |
| 135 // Analog from conio.h | |
| 136 int getche() { | |
| 137 SetTemporaryTermiosSettings(true); | |
| 138 int c = getchar(); | |
| 139 SetTemporaryTermiosSettings(false); | |
| 140 return c; | |
| 141 } | |
| 142 | |
| 143 #endif // !defined(OS_WIN) | |
| 144 | |
| 86 } // namespace | 145 } // namespace |
| 87 | 146 |
| 88 Printer::RegistrationInfo::RegistrationInfo() : state(DEV_REG_UNREGISTERED) { | 147 Printer::RegistrationInfo::RegistrationInfo() |
| 148 : state(DEV_REG_UNREGISTERED), | |
| 149 confirmation_state(CONFIRMATION_PENDING) { | |
| 89 } | 150 } |
| 90 | 151 |
| 91 Printer::RegistrationInfo::~RegistrationInfo() { | 152 Printer::RegistrationInfo::~RegistrationInfo() { |
| 92 } | 153 } |
| 93 | 154 |
| 94 Printer::Printer() : http_server_(this) { | 155 Printer::Printer() : http_server_(this) { |
| 95 } | 156 } |
| 96 | 157 |
| 97 Printer::~Printer() { | 158 Printer::~Printer() { |
| 98 Stop(); | 159 Stop(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 if (status != PrivetHttpServer::REG_ERROR_OK) | 218 if (status != PrivetHttpServer::REG_ERROR_OK) |
| 158 return status; | 219 return status; |
| 159 | 220 |
| 160 if (reg_info_.state != RegistrationInfo::DEV_REG_UNREGISTERED) | 221 if (reg_info_.state != RegistrationInfo::DEV_REG_UNREGISTERED) |
| 161 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; | 222 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; |
| 162 | 223 |
| 163 reg_info_ = RegistrationInfo(); | 224 reg_info_ = RegistrationInfo(); |
| 164 reg_info_.user = user; | 225 reg_info_.user = user; |
| 165 reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_STARTED; | 226 reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_STARTED; |
| 166 | 227 |
| 228 std::cout << kUserConfirmationTitle << std::endl; | |
| 229 base::Time valid_until = base::Time::Now() + | |
| 230 base::TimeDelta::FromSeconds(kUserConfirmationTimeout); | |
| 231 base::MessageLoop::current()->PostTask( | |
| 232 FROM_HERE, | |
| 233 base::Bind(&Printer::WaitUserConfirmation, | |
| 234 base::Unretained(this), valid_until)); | |
| 235 | |
| 167 requester_->StartRegistration(GenerateProxyId(), kPrinterName, user, kCdd); | 236 requester_->StartRegistration(GenerateProxyId(), kPrinterName, user, kCdd); |
| 168 | 237 |
| 169 return PrivetHttpServer::REG_ERROR_OK; | 238 return PrivetHttpServer::REG_ERROR_OK; |
| 170 } | 239 } |
| 171 | 240 |
| 172 bool Printer::CheckXPrivetTokenHeader(const std::string& token) const { | 241 bool Printer::CheckXPrivetTokenHeader(const std::string& token) const { |
| 173 return xtoken_.CheckValidXToken(token); | 242 return xtoken_.CheckValidXToken(token); |
| 174 } | 243 } |
| 175 | 244 |
| 176 bool Printer::IsRegistered() const { | 245 bool Printer::IsRegistered() const { |
| 177 return reg_info_.state == RegistrationInfo::DEV_REG_REGISTERED; | 246 return reg_info_.state == RegistrationInfo::DEV_REG_REGISTERED; |
| 178 } | 247 } |
| 179 | 248 |
| 180 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationGetClaimToken( | 249 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationGetClaimToken( |
| 181 const std::string& user, | 250 const std::string& user, |
| 182 std::string* token, | 251 std::string* token, |
| 183 std::string* claim_url) { | 252 std::string* claim_url) { |
| 184 PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user); | 253 PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user); |
| 185 if (status != PrivetHttpServer::REG_ERROR_OK) | 254 if (status != PrivetHttpServer::REG_ERROR_OK) |
| 186 return status; | 255 return status; |
| 187 | 256 |
| 188 // TODO(maksymb): Add user confirmation. | 257 if (reg_info_.state != RegistrationInfo::DEV_REG_REGISTRATION_STARTED && |
| 258 reg_info_.state != | |
| 259 RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY) | |
| 260 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; | |
| 261 | |
| 262 if (reg_info_.confirmation_state != RegistrationInfo::CONFIRMATION_CONFIRMED) | |
| 263 return ConfirmationToRegistrationError(reg_info_.confirmation_state); | |
| 189 | 264 |
| 190 if (reg_info_.state == RegistrationInfo::DEV_REG_REGISTRATION_STARTED) | 265 if (reg_info_.state == RegistrationInfo::DEV_REG_REGISTRATION_STARTED) |
| 191 return PrivetHttpServer::REG_ERROR_DEVICE_BUSY; | 266 return PrivetHttpServer::REG_ERROR_DEVICE_BUSY; |
| 192 | 267 |
| 193 if (reg_info_.state == | 268 *token = reg_info_.registration_token; |
| 194 RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY) { | 269 *claim_url = reg_info_.complete_invite_url; |
| 195 *token = reg_info_.registration_token; | 270 return PrivetHttpServer::REG_ERROR_OK; |
| 196 *claim_url = reg_info_.complete_invite_url; | |
| 197 return PrivetHttpServer::REG_ERROR_OK; | |
| 198 } | |
| 199 | |
| 200 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; | |
| 201 } | 271 } |
| 202 | 272 |
| 203 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationComplete( | 273 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationComplete( |
| 204 const std::string& user, | 274 const std::string& user, |
| 205 std::string* device_id) { | 275 std::string* device_id) { |
| 206 PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user); | 276 PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user); |
| 207 if (status != PrivetHttpServer::REG_ERROR_OK) | 277 if (status != PrivetHttpServer::REG_ERROR_OK) |
| 208 return status; | 278 return status; |
| 209 | 279 |
| 210 if (reg_info_.state != | 280 if (reg_info_.state != |
| 211 RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY) { | 281 RegistrationInfo::DEV_REG_REGISTRATION_CLAIM_TOKEN_READY) { |
| 212 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; | 282 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; |
| 213 } | 283 } |
| 214 | 284 |
| 285 if (reg_info_.confirmation_state != RegistrationInfo::CONFIRMATION_CONFIRMED) | |
| 286 return ConfirmationToRegistrationError(reg_info_.confirmation_state); | |
| 287 | |
| 215 reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_COMPLETING; | 288 reg_info_.state = RegistrationInfo::DEV_REG_REGISTRATION_COMPLETING; |
| 216 requester_->CompleteRegistration(); | 289 requester_->CompleteRegistration(); |
| 217 | |
| 218 *device_id = reg_info_.device_id; | 290 *device_id = reg_info_.device_id; |
| 219 | 291 |
| 220 return PrivetHttpServer::REG_ERROR_OK; | 292 return PrivetHttpServer::REG_ERROR_OK; |
| 221 } | 293 } |
| 222 | 294 |
| 223 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationCancel( | 295 PrivetHttpServer::RegistrationErrorStatus Printer::RegistrationCancel( |
| 224 const std::string& user) { | 296 const std::string& user) { |
| 225 PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user); | 297 PrivetHttpServer::RegistrationErrorStatus status = CheckCommonRegErrors(user); |
| 226 if (status != PrivetHttpServer::REG_ERROR_OK && | 298 if (status != PrivetHttpServer::REG_ERROR_OK && |
| 227 status != PrivetHttpServer::REG_ERROR_SERVER_ERROR) { | 299 status != PrivetHttpServer::REG_ERROR_SERVER_ERROR) { |
| 228 return status; | 300 return status; |
| 229 } | 301 } |
| 230 | 302 |
| 231 if (reg_info_.state == RegistrationInfo::DEV_REG_UNREGISTERED) | 303 if (reg_info_.state == RegistrationInfo::DEV_REG_UNREGISTERED) |
| 232 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; | 304 return PrivetHttpServer::REG_ERROR_INVALID_ACTION; |
| 233 | 305 |
| 234 reg_info_ = RegistrationInfo(); | 306 reg_info_ = RegistrationInfo(); |
| 307 requester_.reset(new CloudPrintRequester( | |
| 308 base::MessageLoop::current()->message_loop_proxy(), | |
| 309 this)); // Forget all old queries. | |
| 310 | |
| 235 return PrivetHttpServer::REG_ERROR_OK; | 311 return PrivetHttpServer::REG_ERROR_OK; |
| 236 } | 312 } |
| 237 | 313 |
| 238 void Printer::GetRegistrationServerError(std::string* description) { | 314 void Printer::GetRegistrationServerError(std::string* description) { |
| 239 DCHECK_EQ(reg_info_.state, RegistrationInfo::DEV_REG_REGISTRATION_ERROR) << | 315 DCHECK_EQ(reg_info_.state, RegistrationInfo::DEV_REG_REGISTRATION_ERROR) << |
| 240 "Method shouldn't be called when not needed."; | 316 "Method shouldn't be called when not needed."; |
| 241 | 317 |
| 242 *description = reg_info_.error_description; | 318 *description = reg_info_.error_description; |
| 243 } | 319 } |
| 244 | 320 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 299 user != reg_info_.user) { | 375 user != reg_info_.user) { |
| 300 return PrivetHttpServer::REG_ERROR_DEVICE_BUSY; | 376 return PrivetHttpServer::REG_ERROR_DEVICE_BUSY; |
| 301 } | 377 } |
| 302 | 378 |
| 303 if (reg_info_.state == RegistrationInfo::DEV_REG_REGISTRATION_ERROR) | 379 if (reg_info_.state == RegistrationInfo::DEV_REG_REGISTRATION_ERROR) |
| 304 return PrivetHttpServer::REG_ERROR_SERVER_ERROR; | 380 return PrivetHttpServer::REG_ERROR_SERVER_ERROR; |
| 305 | 381 |
| 306 return PrivetHttpServer::REG_ERROR_OK; | 382 return PrivetHttpServer::REG_ERROR_OK; |
| 307 } | 383 } |
| 308 | 384 |
| 385 void Printer::WaitUserConfirmation(base::Time valid_until) { | |
| 386 if (base::Time::Now() > valid_until) { | |
| 387 reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_TIMEOUT; | |
| 388 LOG(INFO) << "Confirmation timeout reached."; | |
| 389 return; | |
| 390 } | |
| 391 | |
| 392 if (kbhit()) { | |
| 393 int c = getche(); | |
| 394 if (c == 'y' || c == 'Y') { | |
| 395 reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_CONFIRMED; | |
| 396 LOG(INFO) << "Registration confirmed by user."; | |
| 397 } else { | |
| 398 reg_info_.confirmation_state = RegistrationInfo::CONFIRMATION_DISCARTED; | |
| 399 LOG(INFO) << "Registration discarted by user."; | |
| 400 } | |
| 401 return; | |
| 402 } | |
| 403 | |
| 404 base::MessageLoop::current()->PostDelayedTask( | |
| 405 FROM_HERE, | |
| 406 base::Bind(&Printer::WaitUserConfirmation, base::Unretained(this), | |
| 407 valid_until), | |
| 408 base::TimeDelta::FromMilliseconds(100)); | |
| 409 } | |
| 410 | |
| 309 std::string Printer::GenerateProxyId() const { | 411 std::string Printer::GenerateProxyId() const { |
| 310 return "{" + base::GenerateGUID() +"}"; | 412 return "{" + base::GenerateGUID() +"}"; |
| 311 } | 413 } |
| 312 | 414 |
| 313 std::vector<std::string> Printer::CreateTxt() const { | 415 std::vector<std::string> Printer::CreateTxt() const { |
| 314 std::vector<std::string> txt; | 416 std::vector<std::string> txt; |
| 315 txt.push_back("txtvers=1"); | 417 txt.push_back("txtvers=1"); |
| 316 txt.push_back("ty=" + std::string(kPrinterName)); | 418 txt.push_back("ty=" + std::string(kPrinterName)); |
| 317 txt.push_back("note=" + std::string(kPrinterDescription)); | 419 txt.push_back("note=" + std::string(kPrinterDescription)); |
| 318 txt.push_back("url=" + std::string(kCloudPrintUrl)); | 420 txt.push_back("url=" + std::string(kCloudPrintUrl)); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 | 499 |
| 398 reg_info_ = RegistrationInfo(); | 500 reg_info_ = RegistrationInfo(); |
| 399 reg_info_.state = RegistrationInfo::DEV_REG_REGISTERED; | 501 reg_info_.state = RegistrationInfo::DEV_REG_REGISTERED; |
| 400 reg_info_.user = user; | 502 reg_info_.user = user; |
| 401 reg_info_.device_id = device_id; | 503 reg_info_.device_id = device_id; |
| 402 reg_info_.refresh_token = refresh_token; | 504 reg_info_.refresh_token = refresh_token; |
| 403 | 505 |
| 404 return true; | 506 return true; |
| 405 } | 507 } |
| 406 | 508 |
| 509 PrivetHttpServer::RegistrationErrorStatus | |
| 510 Printer::ConfirmationToRegistrationError( | |
| 511 RegistrationInfo::ConfirmationState state) { | |
| 512 switch (state) { | |
| 513 case RegistrationInfo::CONFIRMATION_PENDING: | |
| 514 return PrivetHttpServer::REG_ERROR_PENDING_USER_ACTION; | |
| 515 case RegistrationInfo::CONFIRMATION_DISCARTED: | |
| 516 return PrivetHttpServer::REG_ERROR_USER_CANCEL; | |
| 517 case RegistrationInfo::CONFIRMATION_CONFIRMED: | |
| 518 NOTREACHED(); | |
| 519 return PrivetHttpServer::REG_ERROR_OK; | |
| 520 case RegistrationInfo::CONFIRMATION_TIMEOUT: | |
| 521 return PrivetHttpServer::REG_ERROR_CONFIRMATION_TIMEOUT; | |
| 522 default: | |
| 523 NOTREACHED(); | |
| 524 return PrivetHttpServer::REG_ERROR_OK; | |
| 525 } | |
| 526 } | |
| 527 | |
| OLD | NEW |