Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: printing/backend/print_backend_cups.cc

Issue 5846001: Making CUPS calls non-blocking.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « printing/backend/print_backend_consts.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 "printing/backend/print_backend.h" 5 #include "printing/backend/print_backend.h"
6 6
7 #include <dlfcn.h> 7 #include <dlfcn.h>
8 #include <errno.h> 8 #include <errno.h>
9 #if !defined(OS_MACOSX) 9 #if !defined(OS_MACOSX)
10 #include <gcrypt.h> 10 #include <gcrypt.h>
11 #endif 11 #endif
12 #include <pthread.h> 12 #include <pthread.h>
13 13
14 #include "base/file_util.h" 14 #include "base/file_util.h"
15 #include "base/lazy_instance.h" 15 #include "base/lazy_instance.h"
16 #include "base/lock.h" 16 #include "base/lock.h"
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/string_number_conversions.h" 18 #include "base/string_number_conversions.h"
19 #include "base/values.h" 19 #include "base/values.h"
20 #include "googleurl/src/gurl.h" 20 #include "googleurl/src/gurl.h"
21 #include "printing/backend/cups_helper.h" 21 #include "printing/backend/cups_helper.h"
22 #include "printing/backend/print_backend_consts.h"
22 23
23 #if !defined(OS_MACOSX) 24 #if !defined(OS_MACOSX)
24 GCRY_THREAD_OPTION_PTHREAD_IMPL; 25 GCRY_THREAD_OPTION_PTHREAD_IMPL;
25 26
26 namespace { 27 namespace {
27 28
28 // Init GCrypt library (needed for CUPS) using pthreads. 29 // Init GCrypt library (needed for CUPS) using pthreads.
29 // There exists a bug in CUPS library, where it crashed with: "ath.c:184: 30 // There exists a bug in CUPS library, where it crashed with: "ath.c:184:
30 // _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed." 31 // _gcry_ath_mutex_lock: Assertion `*lock == ((ath_mutex_t) 0)' failed."
31 // It happened when multiple threads tried printing simultaneously. 32 // It happened when multiple threads tried printing simultaneously.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 static base::LazyInstance<GcryptInitializer> g_gcrypt_initializer( 70 static base::LazyInstance<GcryptInitializer> g_gcrypt_initializer(
70 base::LINKER_INITIALIZED); 71 base::LINKER_INITIALIZED);
71 72
72 } // namespace 73 } // namespace
73 #endif 74 #endif
74 75
75 namespace printing { 76 namespace printing {
76 77
77 static const char kCUPSPrinterInfoOpt[] = "printer-info"; 78 static const char kCUPSPrinterInfoOpt[] = "printer-info";
78 static const char kCUPSPrinterStateOpt[] = "printer-state"; 79 static const char kCUPSPrinterStateOpt[] = "printer-state";
79 static const char kCUPSPrintServerURL[] = "print_server_url";
80 80
81 class PrintBackendCUPS : public PrintBackend { 81 class PrintBackendCUPS : public PrintBackend {
82 public: 82 public:
83 explicit PrintBackendCUPS(const GURL& print_server_url); 83 PrintBackendCUPS(const GURL& print_server_url, bool blocking);
84 virtual ~PrintBackendCUPS() {} 84 virtual ~PrintBackendCUPS() {}
85 85
86 // PrintBackend implementation. 86 // PrintBackend implementation.
87 virtual void EnumeratePrinters(PrinterList* printer_list); 87 virtual void EnumeratePrinters(PrinterList* printer_list);
88 88
89 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name, 89 virtual bool GetPrinterCapsAndDefaults(const std::string& printer_name,
90 PrinterCapsAndDefaults* printer_info); 90 PrinterCapsAndDefaults* printer_info);
91 91
92 virtual bool IsValidPrinter(const std::string& printer_name); 92 virtual bool IsValidPrinter(const std::string& printer_name);
93 93
94 private: 94 private:
95 // Following functions are wrappers around corresponding CUPS functions. 95 // Following functions are wrappers around corresponding CUPS functions.
96 // <functions>2() are called when print server is specified, and plain 96 // <functions>2() are called when print server is specified, and plain
97 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT 97 // version in another case. There is an issue specifing CUPS_HTTP_DEFAULT
98 // in the <functions>2(), it does not work in CUPS prior to 1.4. 98 // in the <functions>2(), it does not work in CUPS prior to 1.4.
99 int GetDests(cups_dest_t** dests); 99 int GetDests(cups_dest_t** dests);
100 FilePath GetPPD(const char* name); 100 FilePath GetPPD(const char* name);
101 101
102 GURL print_server_url_; 102 GURL print_server_url_;
103 bool blocking_;
103 }; 104 };
104 105
105 PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url) 106 PrintBackendCUPS::PrintBackendCUPS(const GURL& print_server_url, bool blocking)
106 : print_server_url_(print_server_url) { 107 : print_server_url_(print_server_url), blocking_(blocking) {
107 } 108 }
108 109
109 void PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) { 110 void PrintBackendCUPS::EnumeratePrinters(PrinterList* printer_list) {
110 DCHECK(printer_list); 111 DCHECK(printer_list);
111 printer_list->clear(); 112 printer_list->clear();
112 113
113 cups_dest_t* destinations = NULL; 114 cups_dest_t* destinations = NULL;
114 int num_dests = GetDests(&destinations); 115 int num_dests = GetDests(&destinations);
115 116
116 for (int printer_index = 0; printer_index < num_dests; printer_index++) { 117 for (int printer_index = 0; printer_index < num_dests; printer_index++) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 return false; 188 return false;
188 } 189 }
189 190
190 scoped_refptr<PrintBackend> PrintBackend::CreateInstance( 191 scoped_refptr<PrintBackend> PrintBackend::CreateInstance(
191 const DictionaryValue* print_backend_settings) { 192 const DictionaryValue* print_backend_settings) {
192 #if !defined(OS_MACOSX) 193 #if !defined(OS_MACOSX)
193 // Initialize gcrypt library. 194 // Initialize gcrypt library.
194 g_gcrypt_initializer.Get(); 195 g_gcrypt_initializer.Get();
195 #endif 196 #endif
196 197
197 std::string print_server_url_str; 198 std::string print_server_url_str, cups_blocking;
198 if (print_backend_settings) { 199 if (print_backend_settings) {
199 print_backend_settings->GetString(kCUPSPrintServerURL, 200 print_backend_settings->GetString(kCUPSPrintServerURL,
200 &print_server_url_str); 201 &print_server_url_str);
202
203 print_backend_settings->GetString(kCUPSBlocking,
204 &cups_blocking);
201 } 205 }
202 GURL print_server_url(print_server_url_str.c_str()); 206 GURL print_server_url(print_server_url_str.c_str());
203 return new PrintBackendCUPS(print_server_url); 207 return new PrintBackendCUPS(print_server_url, cups_blocking == kValueTrue);
204 } 208 }
205 209
206 int PrintBackendCUPS::GetDests(cups_dest_t** dests) { 210 int PrintBackendCUPS::GetDests(cups_dest_t** dests) {
207 if (print_server_url_.is_empty()) { // Use default (local) print server. 211 if (print_server_url_.is_empty()) { // Use default (local) print server.
208 return cupsGetDests(dests); 212 return cupsGetDests(dests);
209 } else { 213 } else {
210 HttpConnectionCUPS http(print_server_url_); 214 HttpConnectionCUPS http(print_server_url_);
215 http.SetBlocking(blocking_);
211 return cupsGetDests2(http.http(), dests); 216 return cupsGetDests2(http.http(), dests);
212 } 217 }
213 } 218 }
214 219
215 FilePath PrintBackendCUPS::GetPPD(const char* name) { 220 FilePath PrintBackendCUPS::GetPPD(const char* name) {
216 // cupsGetPPD returns a filename stored in a static buffer in CUPS. 221 // cupsGetPPD returns a filename stored in a static buffer in CUPS.
217 // Protect this code with lock. 222 // Protect this code with lock.
218 static Lock ppd_lock; 223 static Lock ppd_lock;
219 AutoLock ppd_autolock(ppd_lock); 224 AutoLock ppd_autolock(ppd_lock);
220 FilePath ppd_path; 225 FilePath ppd_path;
221 const char* ppd_file_path = NULL; 226 const char* ppd_file_path = NULL;
222 if (print_server_url_.is_empty()) { // Use default (local) print server. 227 if (print_server_url_.is_empty()) { // Use default (local) print server.
223 ppd_file_path = cupsGetPPD(name); 228 ppd_file_path = cupsGetPPD(name);
224 if (ppd_file_path) 229 if (ppd_file_path)
225 ppd_path = FilePath(ppd_file_path); 230 ppd_path = FilePath(ppd_file_path);
226 } else { 231 } else {
227 // cupsGetPPD2 gets stuck sometimes in an infinite time due to network 232 // cupsGetPPD2 gets stuck sometimes in an infinite time due to network
228 // configuration/issues. To prevent that, use non-blocking http connection 233 // configuration/issues. To prevent that, use non-blocking http connection
229 // here. 234 // here.
230 // Note: After looking at CUPS sources, it looks like non-blocking 235 // Note: After looking at CUPS sources, it looks like non-blocking
231 // connection will timeout after 10 seconds of no data period. And it will 236 // connection will timeout after 10 seconds of no data period. And it will
232 // return the same way as if data was completely and sucessfully downloaded. 237 // return the same way as if data was completely and sucessfully downloaded.
233 // To distinguish error case from the normal return, will check result file 238 // To distinguish error case from the normal return, will check result file
234 // size agains content length. 239 // size agains content length.
235 HttpConnectionCUPS http(print_server_url_); 240 HttpConnectionCUPS http(print_server_url_);
236 http.SetBlocking(false); 241 http.SetBlocking(blocking_);
237 ppd_file_path = cupsGetPPD2(http.http(), name); 242 ppd_file_path = cupsGetPPD2(http.http(), name);
238 // Check if the get full PPD, since non-blocking call may simply return 243 // Check if the get full PPD, since non-blocking call may simply return
239 // normally after timeout expired. 244 // normally after timeout expired.
240 if (ppd_file_path) { 245 if (ppd_file_path) {
241 ppd_path = FilePath(ppd_file_path); 246 ppd_path = FilePath(ppd_file_path);
242 off_t content_len = httpGetLength2(http.http()); 247 off_t content_len = httpGetLength2(http.http());
243 int64 ppd_size = 0; 248 int64 ppd_size = 0;
244 // This is a heuristic to detect if we reached timeout. If we see content 249 // This is a heuristic to detect if we reached timeout. If we see content
245 // length is larger that the actual file we downloaded it means timeout 250 // length is larger that the actual file we downloaded it means timeout
246 // reached. Sometimes http can be compressed, and in that case the 251 // reached. Sometimes http can be compressed, and in that case the
247 // the content length will be smaller than the actual payload (not sure 252 // the content length will be smaller than the actual payload (not sure
248 // if CUPS support such responses). 253 // if CUPS support such responses).
249 if (!file_util::GetFileSize(ppd_path, &ppd_size) || 254 if (!file_util::GetFileSize(ppd_path, &ppd_size) ||
250 content_len > ppd_size) { 255 content_len > ppd_size) {
251 LOG(ERROR) << "Error downloading PPD file for: " << name 256 LOG(ERROR) << "Error downloading PPD file for: " << name
252 << ", file size: " << ppd_size 257 << ", file size: " << ppd_size
253 << ", content length: " << content_len; 258 << ", content length: " << content_len;
254 file_util::Delete(ppd_path, false); 259 file_util::Delete(ppd_path, false);
255 ppd_path.clear(); 260 ppd_path.clear();
256 } 261 }
257 } 262 }
258 } 263 }
259 return ppd_path; 264 return ppd_path;
260 } 265 }
261 266
262 } // namespace printing 267 } // namespace printing
OLDNEW
« no previous file with comments | « printing/backend/print_backend_consts.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698