diff options
author | gene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-18 17:13:16 +0000 |
---|---|---|
committer | gene@chromium.org <gene@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-18 17:13:16 +0000 |
commit | f15b5a066be23bbb47088f396e275d5b82567f95 (patch) | |
tree | da3a7026fe6163d03a6345a9909d9c081ebf1165 /chrome | |
parent | f74d445459f6bf0479acc08c9c851c12540e6986 (diff) | |
download | chromium_src-f15b5a066be23bbb47088f396e275d5b82567f95.zip chromium_src-f15b5a066be23bbb47088f396e275d5b82567f95.tar.gz chromium_src-f15b5a066be23bbb47088f396e275d5b82567f95.tar.bz2 |
Added functionality in CUPS cloud print proxy to connect to specific
IPP print server. Print server destination is specified in "Service State"
config file.
Due to the GURL parsing implementation, print server url should start
with "http://" scheme.
Also, fixed multithreading raacing condition in CUPS. GCrypt library inside
GnuTLS was not initialized properly. Added initialization code to proxy,
to init gcrypt in pthread mode.
BUG=none
TEST=Specify print server url in "Service State" file. Run proxy. Confirm
that proxy is connected to the specified print server.
Review URL: http://codereview.chromium.org/2859002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50253 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/chrome.gyp | 2 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 3 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 1 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_proxy.cc | 8 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_proxy_backend.cc | 23 | ||||
-rw-r--r-- | chrome/service/cloud_print/cloud_print_proxy_backend.h | 5 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system.h | 10 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_cups.cc | 194 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_dummy.cc | 3 | ||||
-rw-r--r-- | chrome/service/cloud_print/print_system_win.cc | 3 | ||||
-rw-r--r-- | chrome/service/cloud_print/printer_job_handler.cc | 3 |
11 files changed, 212 insertions, 43 deletions
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 01876fb..671e9cf 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1117,6 +1117,8 @@ 'link_settings': { 'libraries': [ '-lcups', + '-lgcrypt', + '-lgnutls', ], }, 'defines': [ diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index c2fd03e..9e13585 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -881,6 +881,9 @@ const wchar_t kCloudPrintXMPPAuthToken[] = L"cloud_print.xmpp_auth_token"; // The email address of the account used to authenticate with the Cloud Print // server. extern const wchar_t kCloudPrintEmail[] = L"cloud_print.email"; +// Settings specific to underlying print system. +extern const wchar_t kCloudPrintPrintSystemSettings[] = + L"cloud_print.print_system_settings"; // Boolean to disable proxy altogether. If true, other proxy // preferences are ignored. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 0e91b2b..192b598 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -328,6 +328,7 @@ extern const wchar_t kCloudPrintProxyId[]; extern const wchar_t kCloudPrintAuthToken[]; extern const wchar_t kCloudPrintXMPPAuthToken[]; extern const wchar_t kCloudPrintEmail[]; +extern const wchar_t kCloudPrintPrintSystemSettings[]; extern const wchar_t kNoProxyServer[]; extern const wchar_t kProxyAutoDetect[]; diff --git a/chrome/service/cloud_print/cloud_print_proxy.cc b/chrome/service/cloud_print/cloud_print_proxy.cc index 3be2f49..3c498df 100644 --- a/chrome/service/cloud_print/cloud_print_proxy.cc +++ b/chrome/service/cloud_print/cloud_print_proxy.cc @@ -35,6 +35,11 @@ void CloudPrintProxy::EnableForUser(const std::string& lsid) { service_prefs_->WritePrefs(); } + // Getting print system specific settings from the preferences. + DictionaryValue* print_system_settings = NULL; + service_prefs_->prefs()->GetDictionary(prefs::kCloudPrintPrintSystemSettings, + &print_system_settings); + // Check if there is an override for the cloud print server URL. std::string cloud_print_server_url_str; service_prefs_->prefs()->GetString(prefs::kCloudPrintServiceURL, @@ -45,7 +50,8 @@ void CloudPrintProxy::EnableForUser(const std::string& lsid) { GURL cloud_print_server_url(cloud_print_server_url_str.c_str()); DCHECK(cloud_print_server_url.is_valid()); - backend_.reset(new CloudPrintProxyBackend(this, cloud_print_server_url)); + backend_.reset(new CloudPrintProxyBackend(this, cloud_print_server_url, + print_system_settings)); // If we have been passed in an LSID, we want to use this to authenticate. // Else we will try and retrieve the last used auth tokens from prefs. if (!lsid.empty()) { diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc index f910a87..683584d 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc @@ -29,8 +29,11 @@ class CloudPrintProxyBackend::Core public PrinterJobHandlerDelegate, public notifier::TalkMediator::Delegate { public: + // It is OK for print_server_url to be empty. In this case system should + // use system default (local) print server. explicit Core(CloudPrintProxyBackend* backend, - const GURL& cloud_print_server_url); + const GURL& cloud_print_server_url, + const DictionaryValue* print_system_settings); // Note: // @@ -127,6 +130,7 @@ class CloudPrintProxyBackend::Core CloudPrintProxyBackend* backend_; GURL cloud_print_server_url_; + scoped_ptr<DictionaryValue> print_system_settings_; // Pointer to current print system. scoped_refptr<cloud_print::PrintSystem> print_system_; // The list of printers to be registered with the cloud print server. @@ -167,12 +171,14 @@ class CloudPrintProxyBackend::Core }; CloudPrintProxyBackend::CloudPrintProxyBackend( - CloudPrintProxyFrontend* frontend, const GURL& cloud_print_server_url) + CloudPrintProxyFrontend* frontend, + const GURL& cloud_print_server_url, + const DictionaryValue* print_system_settings) : core_thread_("Chrome_CloudPrintProxyCoreThread"), frontend_loop_(MessageLoop::current()), frontend_(frontend) { DCHECK(frontend_); - core_ = new Core(this, cloud_print_server_url); + core_ = new Core(this, cloud_print_server_url, print_system_settings); } CloudPrintProxyBackend::~CloudPrintProxyBackend() { @@ -231,10 +237,16 @@ void CloudPrintProxyBackend::HandlePrinterNotification( } CloudPrintProxyBackend::Core::Core(CloudPrintProxyBackend* backend, - const GURL& cloud_print_server_url) + const GURL& cloud_print_server_url, + const DictionaryValue* print_system_settings) : backend_(backend), cloud_print_server_url_(cloud_print_server_url), next_upload_index_(0), server_error_count_(0), next_response_handler_(NULL), new_printers_available_(false) { + if (print_system_settings) { + // It is possible to have no print settings specified. + print_system_settings_.reset( + reinterpret_cast<DictionaryValue*>(print_system_settings->DeepCopy())); + } } void CloudPrintProxyBackend::Core::DoInitializeWithLsid( @@ -279,7 +291,8 @@ void CloudPrintProxyBackend::Core::DoInitializeWithToken( const std::string email, const std::string& proxy_id) { DCHECK(MessageLoop::current() == backend_->core_thread_.message_loop()); - print_system_ = cloud_print::PrintSystem::CreateInstance(); + print_system_ = + cloud_print::PrintSystem::CreateInstance(print_system_settings_.get()); if (!print_system_.get()) { NOTREACHED(); return; // No print system available, fail initalization. diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.h b/chrome/service/cloud_print/cloud_print_proxy_backend.h index bc7da23..c8e3dd89 100644 --- a/chrome/service/cloud_print/cloud_print_proxy_backend.h +++ b/chrome/service/cloud_print/cloud_print_proxy_backend.h @@ -44,8 +44,11 @@ class CloudPrintProxyFrontend { class CloudPrintProxyBackend { public: + // It is OK for print_system_settings to be NULL. In this case system should + // use system default settings. explicit CloudPrintProxyBackend(CloudPrintProxyFrontend* frontend, - const GURL& cloud_print_server_url); + const GURL& cloud_print_server_url, + const DictionaryValue* print_sys_settings); ~CloudPrintProxyBackend(); bool InitializeWithLsid(const std::string& lsid, const std::string& proxy_id); diff --git a/chrome/service/cloud_print/print_system.h b/chrome/service/cloud_print/print_system.h index 579026c..23f6f41 100644 --- a/chrome/service/cloud_print/print_system.h +++ b/chrome/service/cloud_print/print_system.h @@ -11,6 +11,8 @@ #include "base/file_path.h" #include "base/ref_counted.h" +#include "base/values.h" +#include "googleurl/src/gurl.h" // This is the interface for platform-specific code for cloud print namespace cloud_print { @@ -149,9 +151,11 @@ class PrintSystem : public base::RefCountedThreadSafe<PrintSystem> { // Generate unique for proxy. static std::string GenerateProxyId(); - // Call this function to obtain current printing system. Return NULL if no - // print system available. Delete returned PrintSystem pointer using delete. - static scoped_refptr<PrintSystem> CreateInstance(); + // Call this function to obtain printing system for specified print server. + // If print settings are NULL, default settings will be used. + // Return NULL if no print system available. + static scoped_refptr<PrintSystem> CreateInstance( + const DictionaryValue* print_system_settings); }; diff --git a/chrome/service/cloud_print/print_system_cups.cc b/chrome/service/cloud_print/print_system_cups.cc index 4e3e324..2f32a5a 100644 --- a/chrome/service/cloud_print/print_system_cups.cc +++ b/chrome/service/cloud_print/print_system_cups.cc @@ -8,6 +8,11 @@ #include <list> #include <map> +#include <gnutls/gnutls.h> +#include <gcrypt.h> +#include <errno.h> +#include <pthread.h> + #include "base/json/json_reader.h" #include "base/file_path.h" #include "base/file_util.h" @@ -17,16 +22,72 @@ #include "base/rand_util.h" #include "base/string_util.h" #include "base/task.h" -#include "base/values.h" #include "base/utf_string_conversions.h" namespace cloud_print { static const char kCUPSPrinterInfoOpt[] = "printer-info"; static const char kCUPSPrinterStateOpt[] = "printer-state"; +static const wchar_t kCUPSPrintServerURL[] = L"print_server_url"; + +// Default port for IPP print servers. +static const int kDefaultIPPServerPort = 631; + +// Init GCrypt library (needed for CUPS) using pthreads. +// I've hit a bug in CUPS library, when it crashed with: "ath.c:184: +// _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed." +// It happened whe multiple threads tried printing simultaneously. +// Google search for 'gnutls thread safety' provided with following solution. + +GCRY_THREAD_OPTION_PTHREAD_IMPL; + +void init_gcrypt() { + static bool gcrypt_initialized = false; + if (!gcrypt_initialized) { + gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + gnutls_global_init(); + gcrypt_initialized = true; + } +} + +// Helper wrapper around http_t structure, with connection and cleanup +// functionality. +class HttpConnectionCUPS { + public: + explicit HttpConnectionCUPS(const GURL& print_server_url) : http_(NULL) { + // If we have an empty url, use default print server. + if (print_server_url.is_empty()) + return; + + int port = print_server_url.IntPort(); + if (port == url_parse::PORT_UNSPECIFIED) + port = kDefaultIPPServerPort; + + http_ = httpConnectEncrypt(print_server_url.host().c_str(), port, + HTTP_ENCRYPT_NEVER); + if (http_ == NULL) { + LOG(ERROR) << "CP_CUPS: Failed connecting to print server: " << + print_server_url; + } + } + + ~HttpConnectionCUPS() { + if (http_ != NULL) + httpClose(http_); + } + + http_t* http() { + return http_; + } + + private: + http_t* http_; +}; class PrintSystemCUPS : public PrintSystem { public: + explicit PrintSystemCUPS(const GURL& print_server_url); + virtual void EnumeratePrinters(PrinterList* printer_list); virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, @@ -123,14 +184,32 @@ class PrintSystemCUPS : public PrintSystem { bool GetPrinterInfo(const std::string& printer_name, PrinterBasicInfo* info); bool ParsePrintTicket(const std::string& print_ticket, std::map<std::string, std::string>* options); + + private: + // Following functions are wrappers around corresponding CUPS functions. + // <functions>2() are called when print server is specified, and plain + // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT + // in the <functions>2(), it does not work in CUPS prior to 1.4. + int GetDests(cups_dest_t** dests); + FilePath GetPPD(const char* name); + int PrintFile(const char* name, const char* filename, const char* title, + int num_options, cups_option_t* options); + int GetJobs(cups_job_t** jobs, const char* name, + int myjobs, int whichjobs); + + GURL print_server_url_; }; +PrintSystemCUPS::PrintSystemCUPS(const GURL& print_server_url) + : print_server_url_(print_server_url) { +} + void PrintSystemCUPS::EnumeratePrinters(PrinterList* printer_list) { DCHECK(printer_list); printer_list->clear(); cups_dest_t* destinations = NULL; - int num_dests = cupsGetDests(&destinations); + int num_dests = GetDests(&destinations); for (int printer_index = 0; printer_index < num_dests; printer_index++) { const cups_dest_t& printer = destinations[printer_index]; @@ -159,28 +238,19 @@ void PrintSystemCUPS::EnumeratePrinters(PrinterList* printer_list) { cupsFreeDests(num_dests, destinations); - DLOG(INFO) << "CP_CUPS: Enumerated " << printer_list->size() << " printers."; + LOG(INFO) << "CP_CUPS: Enumerated " << printer_list->size() << " printers."; } bool PrintSystemCUPS::GetPrinterCapsAndDefaults(const std::string& printer_name, PrinterCapsAndDefaults* printer_info) { DCHECK(printer_info); - DLOG(INFO) << "CP_CUPS: Getting Caps and Defaults for: " << printer_name; - - static Lock ppd_lock; - // cupsGetPPD returns a filename stored in a static buffer in CUPS. - // Protect this code with lock. - ppd_lock.Acquire(); - FilePath ppd_path; - const char* ppd_file_path = cupsGetPPD(printer_name.c_str()); - if (ppd_file_path) - ppd_path = FilePath(ppd_file_path); - ppd_lock.Release(); + LOG(INFO) << "CP_CUPS: Getting Caps and Defaults for: " << printer_name; + FilePath ppd_path(GetPPD(printer_name.c_str())); // In some cases CUPS failed to get ppd file. if (ppd_path.empty()) { - DLOG(ERROR) << "CP_CUPS: Failed to get PPD for: " << printer_name; + LOG(ERROR) << "CP_CUPS: Failed to get PPD for: " << printer_name; return false; } @@ -238,10 +308,10 @@ bool PrintSystemCUPS::SpoolPrintJob(const std::string& print_ticket, PlatformJobId* job_id_ret) { DCHECK(job_id_ret); - DLOG(INFO) << "CP_CUPS: Spooling print job for: " << printer_name; + LOG(INFO) << "CP_CUPS: Spooling print job for: " << printer_name; // We need to store options as char* string for the duration of the - // cupsPrintFile call. We'll use map here to store options, since + // cupsPrintFile2 call. We'll use map here to store options, since // Dictionary value from JSON parser returns wchat_t. std::map<std::string, std::string> options; bool res = ParsePrintTicket(print_ticket, &options); @@ -256,13 +326,13 @@ bool PrintSystemCUPS::SpoolPrintJob(const std::string& print_ticket, cups_options.push_back(opt); } - int job_id = cupsPrintFile(printer_name.c_str(), - print_data_file_path.value().c_str(), - job_title.c_str(), - cups_options.size(), - &(cups_options[0])); + int job_id = PrintFile(printer_name.c_str(), + print_data_file_path.value().c_str(), + job_title.c_str(), + cups_options.size(), + &(cups_options[0])); - DLOG(INFO) << "CP_CUPS: Job spooled, id: " << job_id; + LOG(INFO) << "CP_CUPS: Job spooled, id: " << job_id; if (job_id == 0) return false; @@ -276,11 +346,8 @@ bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name, PrintJobDetails *job_details) { DCHECK(job_details); - DLOG(INFO) << "CP_CUPS: Getting job details for: " << printer_name << - " job_id: " << job_id; - cups_job_t* jobs = NULL; - int num_jobs = cupsGetJobs(&jobs, printer_name.c_str(), 1, -1); + int num_jobs = GetJobs(&jobs, printer_name.c_str(), 1, -1); bool found = false; for (int i = 0; i < num_jobs; i++) { @@ -310,6 +377,13 @@ bool PrintSystemCUPS::GetJobDetails(const std::string& printer_name, } } + if (found) + LOG(INFO) << "CP_CUPS: Job details for: " << printer_name << + " job_id: " << job_id << " job status: " << job_details->status; + else + LOG(WARNING) << "CP_CUPS: Job not found for: " << printer_name << + " job_id: " << job_id; + cupsFreeJobs(num_jobs, jobs); return found; } @@ -318,7 +392,7 @@ bool PrintSystemCUPS::GetPrinterInfo(const std::string& printer_name, PrinterBasicInfo* info) { DCHECK(info); - DLOG(INFO) << "CP_CUPS: Getting printer info for: " << printer_name; + LOG(INFO) << "CP_CUPS: Getting printer info for: " << printer_name; // This is not very efficient way to get specific printer info. CUPS 1.4 // supports cupsGetNamedDest() function. However, CUPS 1.4 is not available @@ -361,8 +435,68 @@ std::string PrintSystem::GenerateProxyId() { return id; } -scoped_refptr<PrintSystem> PrintSystem::CreateInstance() { - return new PrintSystemCUPS; +scoped_refptr<PrintSystem> PrintSystem::CreateInstance( + const DictionaryValue* print_system_settings) { + // Initialize gcrypt library. + init_gcrypt(); + + std::string print_server_url_str; + if (print_system_settings) { + print_system_settings->GetString( + kCUPSPrintServerURL, &print_server_url_str); + } + GURL print_server_url(print_server_url_str.c_str()); + return new PrintSystemCUPS(print_server_url); +} + +int PrintSystemCUPS::GetDests(cups_dest_t** dests) { + if (print_server_url_.is_empty()) { // Use default (local) print server. + return cupsGetDests(dests); + } else { + HttpConnectionCUPS http(print_server_url_); + return cupsGetDests2(http.http(), dests); + } +} + +FilePath PrintSystemCUPS::GetPPD(const char* name) { + // cupsGetPPD returns a filename stored in a static buffer in CUPS. + // Protect this code with lock. + static Lock ppd_lock; + ppd_lock.Acquire(); + FilePath ppd_path; + const char* ppd_file_path = NULL; + if (print_server_url_.is_empty()) { // Use default (local) print server. + ppd_file_path = cupsGetPPD(name); + } else { + HttpConnectionCUPS http(print_server_url_); + ppd_file_path = cupsGetPPD2(http.http(), name); + } + if (ppd_file_path) + ppd_path = FilePath(ppd_file_path); + ppd_lock.Release(); + return ppd_path; +} + +int PrintSystemCUPS::PrintFile(const char* name, const char* filename, + const char* title, int num_options, + cups_option_t* options) { + if (print_server_url_.is_empty()) { // Use default (local) print server. + return cupsPrintFile(name, filename, title, num_options, options); + } else { + HttpConnectionCUPS http(print_server_url_); + return cupsPrintFile2(http.http(), name, filename, + title, num_options, options); + } +} + +int PrintSystemCUPS::GetJobs(cups_job_t** jobs, const char* name, + int myjobs, int whichjobs) { + if (print_server_url_.is_empty()) { // Use default (local) print server. + return cupsGetJobs(jobs, name, myjobs, whichjobs); + } else { + HttpConnectionCUPS http(print_server_url_); + return cupsGetJobs2(http.http(), jobs, name, myjobs, whichjobs); + } } } // namespace cloud_print diff --git a/chrome/service/cloud_print/print_system_dummy.cc b/chrome/service/cloud_print/print_system_dummy.cc index 49e481d..ea3fac1 100644 --- a/chrome/service/cloud_print/print_system_dummy.cc +++ b/chrome/service/cloud_print/print_system_dummy.cc @@ -17,7 +17,8 @@ std::string PrintSystem::GenerateProxyId() { return std::string(); } -scoped_refptr<PrintSystem> PrintSystem::CreateInstance() { +scoped_refptr<PrintSystem> PrintSystem::CreateInstance( + const DictionaryValue* print_system_settings) { NOTREACHED(); return NULL; } diff --git a/chrome/service/cloud_print/print_system_win.cc b/chrome/service/cloud_print/print_system_win.cc index 58a27fa..d1e00c8 100644 --- a/chrome/service/cloud_print/print_system_win.cc +++ b/chrome/service/cloud_print/print_system_win.cc @@ -610,7 +610,8 @@ std::string PrintSystem::GenerateProxyId() { return ret; } -scoped_refptr<PrintSystem> PrintSystem::CreateInstance() { +scoped_refptr<PrintSystem> PrintSystem::CreateInstance( + const DictionaryValue* print_system_settings) { return new PrintSystemWin; } diff --git a/chrome/service/cloud_print/printer_job_handler.cc b/chrome/service/cloud_print/printer_job_handler.cc index 8e765b6..f99e461 100644 --- a/chrome/service/cloud_print/printer_job_handler.cc +++ b/chrome/service/cloud_print/printer_job_handler.cc @@ -57,7 +57,8 @@ bool PrinterJobHandler::Initialize() { } PrinterJobHandler::~PrinterJobHandler() { - printer_watcher_->StopWatching(); + if (printer_watcher_) + printer_watcher_->StopWatching(); } void PrinterJobHandler::Reset() { |