diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llxmlrpctransaction.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llxmlrpctransaction.cpp')
-rw-r--r-- | linden/indra/newview/llxmlrpctransaction.cpp | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/linden/indra/newview/llxmlrpctransaction.cpp b/linden/indra/newview/llxmlrpctransaction.cpp new file mode 100644 index 0000000..9b8a872 --- /dev/null +++ b/linden/indra/newview/llxmlrpctransaction.cpp | |||
@@ -0,0 +1,596 @@ | |||
1 | /** | ||
2 | * @file llxmlrpctransaction.cpp | ||
3 | * @brief LLXMLRPCTransaction and related class implementations | ||
4 | * | ||
5 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include "llxmlrpctransaction.h" | ||
31 | |||
32 | #include "llviewercontrol.h" | ||
33 | |||
34 | // Have to include these last to avoid queue redefinition! | ||
35 | #include <curl/curl.h> | ||
36 | #include <xmlrpc-epi/xmlrpc.h> | ||
37 | |||
38 | #include "viewer.h" | ||
39 | |||
40 | LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const | ||
41 | { | ||
42 | return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id)); | ||
43 | } | ||
44 | |||
45 | std::string LLXMLRPCValue::asString() const | ||
46 | { | ||
47 | const char* s = XMLRPC_GetValueString(mV); | ||
48 | return s ? s : ""; | ||
49 | } | ||
50 | |||
51 | int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); } | ||
52 | bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; } | ||
53 | double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); } | ||
54 | |||
55 | LLXMLRPCValue LLXMLRPCValue::rewind() | ||
56 | { | ||
57 | return LLXMLRPCValue(XMLRPC_VectorRewind(mV)); | ||
58 | } | ||
59 | |||
60 | LLXMLRPCValue LLXMLRPCValue::next() | ||
61 | { | ||
62 | return LLXMLRPCValue(XMLRPC_VectorNext(mV)); | ||
63 | } | ||
64 | |||
65 | bool LLXMLRPCValue::isValid() const | ||
66 | { | ||
67 | return mV != NULL; | ||
68 | } | ||
69 | |||
70 | LLXMLRPCValue LLXMLRPCValue::createArray() | ||
71 | { | ||
72 | return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array)); | ||
73 | } | ||
74 | |||
75 | LLXMLRPCValue LLXMLRPCValue::createStruct() | ||
76 | { | ||
77 | return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct)); | ||
78 | } | ||
79 | |||
80 | |||
81 | void LLXMLRPCValue::append(LLXMLRPCValue& v) | ||
82 | { | ||
83 | XMLRPC_AddValueToVector(mV, v.mV); | ||
84 | } | ||
85 | |||
86 | void LLXMLRPCValue::appendString(const std::string& v) | ||
87 | { | ||
88 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0)); | ||
89 | } | ||
90 | |||
91 | void LLXMLRPCValue::appendInt(int v) | ||
92 | { | ||
93 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v)); | ||
94 | } | ||
95 | |||
96 | void LLXMLRPCValue::appendBool(bool v) | ||
97 | { | ||
98 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v)); | ||
99 | } | ||
100 | |||
101 | void LLXMLRPCValue::appendDouble(double v) | ||
102 | { | ||
103 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v)); | ||
104 | } | ||
105 | |||
106 | |||
107 | void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v) | ||
108 | { | ||
109 | XMLRPC_SetValueID(v.mV, id, 0); | ||
110 | XMLRPC_AddValueToVector(mV, v.mV); | ||
111 | } | ||
112 | |||
113 | void LLXMLRPCValue::appendString(const char* id, const std::string& v) | ||
114 | { | ||
115 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0)); | ||
116 | } | ||
117 | |||
118 | void LLXMLRPCValue::appendInt(const char* id, int v) | ||
119 | { | ||
120 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v)); | ||
121 | } | ||
122 | |||
123 | void LLXMLRPCValue::appendBool(const char* id, bool v) | ||
124 | { | ||
125 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v)); | ||
126 | } | ||
127 | |||
128 | void LLXMLRPCValue::appendDouble(const char* id, double v) | ||
129 | { | ||
130 | XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v)); | ||
131 | } | ||
132 | |||
133 | void LLXMLRPCValue::free() | ||
134 | { | ||
135 | XMLRPC_CleanupValue(mV); | ||
136 | mV = NULL; | ||
137 | } | ||
138 | |||
139 | XMLRPC_VALUE LLXMLRPCValue::getValue() const | ||
140 | { | ||
141 | return mV; | ||
142 | } | ||
143 | |||
144 | |||
145 | class LLXMLRPCTransaction::Impl | ||
146 | { | ||
147 | public: | ||
148 | typedef LLXMLRPCTransaction::Status Status; | ||
149 | |||
150 | CURL* mCurl; | ||
151 | CURLM* mCurlMulti; | ||
152 | |||
153 | Status mStatus; | ||
154 | CURLcode mCurlCode; | ||
155 | std::string mStatusMessage; | ||
156 | std::string mStatusURI; | ||
157 | |||
158 | char mCurlErrorBuffer[CURL_ERROR_SIZE]; | ||
159 | |||
160 | std::string mURI; | ||
161 | char* mRequestText; | ||
162 | int mRequestTextSize; | ||
163 | |||
164 | std::string mProxyAddress; | ||
165 | struct curl_slist* mHeaders; | ||
166 | |||
167 | std::string mResponseText; | ||
168 | XMLRPC_REQUEST mResponse; | ||
169 | |||
170 | Impl(const std::string& uri, XMLRPC_REQUEST request, bool useGzip); | ||
171 | Impl(const std::string& uri, | ||
172 | const std::string& method, LLXMLRPCValue params, bool useGzip); | ||
173 | ~Impl(); | ||
174 | |||
175 | bool process(); | ||
176 | |||
177 | void setStatus(Status code, | ||
178 | const std::string& message = "", const std::string& uri = ""); | ||
179 | void setCurlStatus(CURLcode); | ||
180 | |||
181 | private: | ||
182 | void init(XMLRPC_REQUEST request, bool useGzip); | ||
183 | |||
184 | static size_t curlDownloadCallback( | ||
185 | void* data, size_t size, size_t nmemb, void* user_data); | ||
186 | }; | ||
187 | |||
188 | LLXMLRPCTransaction::Impl::Impl(const std::string& uri, | ||
189 | XMLRPC_REQUEST request, bool useGzip) | ||
190 | : mCurl(0), mCurlMulti(0), | ||
191 | mStatus(LLXMLRPCTransaction::StatusNotStarted), | ||
192 | mURI(uri), | ||
193 | mRequestText(0), mHeaders(0), | ||
194 | mResponse(0) | ||
195 | { | ||
196 | init(request, useGzip); | ||
197 | } | ||
198 | |||
199 | |||
200 | LLXMLRPCTransaction::Impl::Impl(const std::string& uri, | ||
201 | const std::string& method, LLXMLRPCValue params, bool useGzip) | ||
202 | : mCurl(0), mCurlMulti(0), | ||
203 | mStatus(LLXMLRPCTransaction::StatusNotStarted), | ||
204 | mURI(uri), | ||
205 | mRequestText(0), mHeaders(0), | ||
206 | mResponse(0) | ||
207 | { | ||
208 | XMLRPC_REQUEST request = XMLRPC_RequestNew(); | ||
209 | XMLRPC_RequestSetMethodName(request, method.c_str()); | ||
210 | XMLRPC_RequestSetRequestType(request, xmlrpc_request_call); | ||
211 | XMLRPC_RequestSetData(request, params.getValue()); | ||
212 | |||
213 | init(request, useGzip); | ||
214 | } | ||
215 | |||
216 | |||
217 | |||
218 | |||
219 | void LLXMLRPCTransaction::Impl::init(XMLRPC_REQUEST request, bool useGzip) | ||
220 | { | ||
221 | mCurl = curl_easy_init(); | ||
222 | |||
223 | if (gSavedSettings.getBOOL("BrowserProxyEnabled")) | ||
224 | { | ||
225 | mProxyAddress = gSavedSettings.getString("BrowserProxyAddress"); | ||
226 | S32 port = gSavedSettings.getS32 ( "BrowserProxyPort" ); | ||
227 | |||
228 | // tell curl about the settings | ||
229 | curl_easy_setopt(mCurl, CURLOPT_PROXY, mProxyAddress.c_str()); | ||
230 | curl_easy_setopt(mCurl, CURLOPT_PROXYPORT, (long)port); | ||
231 | curl_easy_setopt(mCurl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); | ||
232 | }; | ||
233 | |||
234 | // curl_easy_setopt(mCurl, CURLOPT_VERBOSE, 1); // usefull for debugging | ||
235 | curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, 1); | ||
236 | curl_easy_setopt(mCurl, CURLOPT_WRITEFUNCTION, &curlDownloadCallback); | ||
237 | curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, this); | ||
238 | curl_easy_setopt(mCurl, CURLOPT_ERRORBUFFER, &mCurlErrorBuffer); | ||
239 | curl_easy_setopt(mCurl, CURLOPT_CAINFO, gDirUtilp->getCAFile().c_str()); | ||
240 | curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, gVerifySSLCert); | ||
241 | |||
242 | /* Setting the DNS cache timeout to -1 disables it completely. | ||
243 | This might help with bug #503 */ | ||
244 | curl_easy_setopt(mCurl, CURLOPT_DNS_CACHE_TIMEOUT, -1); | ||
245 | |||
246 | mHeaders = curl_slist_append(mHeaders, "Content-Type: text/xml"); | ||
247 | curl_easy_setopt(mCurl, CURLOPT_URL, mURI.c_str()); | ||
248 | curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaders); | ||
249 | if (useGzip) | ||
250 | { | ||
251 | curl_easy_setopt(mCurl, CURLOPT_ENCODING, ""); | ||
252 | } | ||
253 | |||
254 | mRequestText = XMLRPC_REQUEST_ToXML(request, &mRequestTextSize); | ||
255 | if (mRequestText) | ||
256 | { | ||
257 | curl_easy_setopt(mCurl, CURLOPT_POSTFIELDS, mRequestText); | ||
258 | curl_easy_setopt(mCurl, CURLOPT_POSTFIELDSIZE, mRequestTextSize); | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 | setStatus(StatusOtherError); | ||
263 | } | ||
264 | |||
265 | mCurlMulti = curl_multi_init(); | ||
266 | curl_multi_add_handle(mCurlMulti, mCurl); | ||
267 | } | ||
268 | |||
269 | |||
270 | LLXMLRPCTransaction::Impl::~Impl() | ||
271 | { | ||
272 | if (mResponse) | ||
273 | { | ||
274 | XMLRPC_RequestFree(mResponse, 1); | ||
275 | } | ||
276 | |||
277 | if (mHeaders) | ||
278 | { | ||
279 | curl_slist_free_all(mHeaders); | ||
280 | } | ||
281 | |||
282 | if (mRequestText) | ||
283 | { | ||
284 | XMLRPC_Free(mRequestText); | ||
285 | } | ||
286 | |||
287 | if (mCurl) | ||
288 | { | ||
289 | if (mCurlMulti) | ||
290 | { | ||
291 | curl_multi_remove_handle(mCurlMulti, mCurl); | ||
292 | } | ||
293 | curl_easy_cleanup(mCurl); | ||
294 | } | ||
295 | |||
296 | if (mCurlMulti) | ||
297 | { | ||
298 | curl_multi_cleanup(mCurlMulti); | ||
299 | } | ||
300 | |||
301 | } | ||
302 | |||
303 | bool LLXMLRPCTransaction::Impl::process() | ||
304 | { | ||
305 | switch(mStatus) | ||
306 | { | ||
307 | case LLXMLRPCTransaction::StatusComplete: | ||
308 | case LLXMLRPCTransaction::StatusCURLError: | ||
309 | case LLXMLRPCTransaction::StatusXMLRPCError: | ||
310 | case LLXMLRPCTransaction::StatusOtherError: | ||
311 | { | ||
312 | return true; | ||
313 | } | ||
314 | |||
315 | case LLXMLRPCTransaction::StatusNotStarted: | ||
316 | { | ||
317 | setStatus(LLXMLRPCTransaction::StatusStarted); | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | default: | ||
322 | { | ||
323 | // continue onward | ||
324 | } | ||
325 | } | ||
326 | |||
327 | const F32 MAX_PROCESSING_TIME = 0.05f; | ||
328 | LLTimer timer; | ||
329 | int count; | ||
330 | |||
331 | while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(mCurlMulti, &count)) | ||
332 | { | ||
333 | if (timer.getElapsedTimeF32() >= MAX_PROCESSING_TIME) | ||
334 | { | ||
335 | return false; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | while(CURLMsg* curl_msg = curl_multi_info_read(mCurlMulti, &count)) | ||
340 | { | ||
341 | if (CURLMSG_DONE == curl_msg->msg) | ||
342 | { | ||
343 | if (curl_msg->data.result != CURLE_OK) | ||
344 | { | ||
345 | setCurlStatus(curl_msg->data.result); | ||
346 | llalerts << "LLXMLRPCTransaction CURL error " | ||
347 | << mCurlCode << ": " << mCurlErrorBuffer << llendl; | ||
348 | llalerts << "LLXMLRPCTransaction request URI: " | ||
349 | << mURI << llendl; | ||
350 | |||
351 | return true; | ||
352 | } | ||
353 | |||
354 | setStatus(LLXMLRPCTransaction::StatusComplete); | ||
355 | |||
356 | mResponse = XMLRPC_REQUEST_FromXML( | ||
357 | mResponseText.data(), mResponseText.size(), NULL); | ||
358 | |||
359 | bool hasError = false; | ||
360 | bool hasFault = false; | ||
361 | int faultCode = 0; | ||
362 | std::string faultString; | ||
363 | |||
364 | LLXMLRPCValue error(XMLRPC_RequestGetError(mResponse)); | ||
365 | if (error.isValid()) | ||
366 | { | ||
367 | hasError = true; | ||
368 | faultCode = error["faultCode"].asInt(); | ||
369 | faultString = error["faultString"].asString(); | ||
370 | } | ||
371 | else if (XMLRPC_ResponseIsFault(mResponse)) | ||
372 | { | ||
373 | hasFault = true; | ||
374 | faultCode = XMLRPC_GetResponseFaultCode(mResponse); | ||
375 | faultString = XMLRPC_GetResponseFaultString(mResponse); | ||
376 | } | ||
377 | |||
378 | if (hasError || hasFault) | ||
379 | { | ||
380 | setStatus(LLXMLRPCTransaction::StatusXMLRPCError); | ||
381 | |||
382 | llalerts << "LLXMLRPCTransaction XMLRPC " | ||
383 | << (hasError ? "error " : "fault ") | ||
384 | << faultCode << ": " | ||
385 | << faultString << llendl; | ||
386 | llalerts << "LLXMLRPCTransaction request URI: " | ||
387 | << mURI << llendl; | ||
388 | } | ||
389 | |||
390 | return true; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | return false; | ||
395 | } | ||
396 | |||
397 | void LLXMLRPCTransaction::Impl::setStatus(Status status, | ||
398 | const std::string& message, const std::string& uri) | ||
399 | { | ||
400 | mStatus = status; | ||
401 | mStatusMessage = message; | ||
402 | mStatusURI = uri; | ||
403 | |||
404 | if (mStatusMessage.empty()) | ||
405 | { | ||
406 | switch (mStatus) | ||
407 | { | ||
408 | case StatusNotStarted: | ||
409 | mStatusMessage = "(not started)"; | ||
410 | break; | ||
411 | |||
412 | case StatusStarted: | ||
413 | mStatusMessage = "(waiting for server response)"; | ||
414 | break; | ||
415 | |||
416 | case StatusDownloading: | ||
417 | mStatusMessage = "(reading server response)"; | ||
418 | break; | ||
419 | |||
420 | case StatusComplete: | ||
421 | mStatusMessage = "(done)"; | ||
422 | break; | ||
423 | |||
424 | default: | ||
425 | // Usually this means that there's a problem with the login server, | ||
426 | // not with the client. Direct user to status page. JC | ||
427 | mStatusMessage = | ||
428 | "Despite our best efforts, something unexpected has gone wrong. \n" | ||
429 | " \n" | ||
430 | "Please check www.secondlife.com/status and the Second Life \n" | ||
431 | "Announcements forum to see if there is a known problem with \n" | ||
432 | "the service."; | ||
433 | mStatusURI = "http://secondlife.com/status/"; | ||
434 | /* | ||
435 | mStatusMessage = | ||
436 | "Despite our best efforts, something unexpected has gone wrong.\n" | ||
437 | "Please go to the Support section of the SecondLife.com web site\n" | ||
438 | "and report the problem. If possible, include your SecondLife.log\n" | ||
439 | "file from:\n" | ||
440 | #if LL_WINDOWS | ||
441 | "C:\\Documents and Settings\\<name>\\Application Data\\SecondLife\\logs\n" | ||
442 | #elif LL_DARWIN | ||
443 | "~/Library/Application Support/SecondLife/logs\n" | ||
444 | #elif LL_LINUX | ||
445 | "~/.secondlife/logs\n" | ||
446 | #else | ||
447 | #error "Need platform here." | ||
448 | #endif | ||
449 | "Thank you."; | ||
450 | mStatusURI = "http://secondlife.com/community/support.php"; | ||
451 | */ | ||
452 | } | ||
453 | } | ||
454 | } | ||
455 | |||
456 | void LLXMLRPCTransaction::Impl::setCurlStatus(CURLcode code) | ||
457 | { | ||
458 | std::string message; | ||
459 | std::string uri = "http://secondlife.com/community/support.php"; | ||
460 | |||
461 | switch (code) | ||
462 | { | ||
463 | case CURLE_COULDNT_RESOLVE_HOST: | ||
464 | message = | ||
465 | "DNS could not resolve the host name.\n" | ||
466 | "Please verify that you can connect to the www.secondlife.com\n" | ||
467 | "web site. If you can, but continue to receive this error,\n" | ||
468 | "please go to the support section and report this problem."; | ||
469 | break; | ||
470 | |||
471 | case CURLE_SSL_PEER_CERTIFICATE: | ||
472 | message = | ||
473 | "The login server couldn't verify itself via SSL.\n" | ||
474 | "If you continue to receive this error, please go\n" | ||
475 | "to the Support section of the SecondLife.com web site\n" | ||
476 | "and report the problem."; | ||
477 | break; | ||
478 | |||
479 | case CURLE_SSL_CACERT: | ||
480 | case CURLE_SSL_CONNECT_ERROR: | ||
481 | message = | ||
482 | "Often this means that your computer\'s clock is set incorrectly.\n" | ||
483 | "Please go to Control Panels and make sure the time and date\n" | ||
484 | "are set correctly.\n" | ||
485 | "\n" | ||
486 | "If you continue to receive this error, please go\n" | ||
487 | "to the Support section of the SecondLife.com web site\n" | ||
488 | "and report the problem."; | ||
489 | break; | ||
490 | |||
491 | default: | ||
492 | break; | ||
493 | } | ||
494 | |||
495 | mCurlCode = code; | ||
496 | setStatus(StatusCURLError, message, uri); | ||
497 | } | ||
498 | |||
499 | size_t LLXMLRPCTransaction::Impl::curlDownloadCallback( | ||
500 | void* data, size_t size, size_t nmemb, void* user_data) | ||
501 | { | ||
502 | Impl& impl(*(Impl*)user_data); | ||
503 | |||
504 | size_t n = size * nmemb; | ||
505 | |||
506 | impl.mResponseText.append((const char*)data, n); | ||
507 | |||
508 | if (impl.mStatus == LLXMLRPCTransaction::StatusStarted) | ||
509 | { | ||
510 | impl.setStatus(LLXMLRPCTransaction::StatusDownloading); | ||
511 | } | ||
512 | |||
513 | return n; | ||
514 | } | ||
515 | |||
516 | |||
517 | LLXMLRPCTransaction::LLXMLRPCTransaction( | ||
518 | const std::string& uri, XMLRPC_REQUEST request, bool useGzip) | ||
519 | : impl(* new Impl(uri, request, useGzip)) | ||
520 | { } | ||
521 | |||
522 | |||
523 | LLXMLRPCTransaction::LLXMLRPCTransaction( | ||
524 | const std::string& uri, | ||
525 | const std::string& method, LLXMLRPCValue params, bool useGzip) | ||
526 | : impl(* new Impl(uri, method, params, useGzip)) | ||
527 | { } | ||
528 | |||
529 | LLXMLRPCTransaction::~LLXMLRPCTransaction() | ||
530 | { | ||
531 | delete &impl; | ||
532 | } | ||
533 | |||
534 | bool LLXMLRPCTransaction::process() | ||
535 | { | ||
536 | return impl.process(); | ||
537 | } | ||
538 | |||
539 | LLXMLRPCTransaction::Status LLXMLRPCTransaction::status(int* curlCode) | ||
540 | { | ||
541 | if (curlCode) | ||
542 | { | ||
543 | *curlCode = | ||
544 | (impl.mStatus == StatusCURLError) | ||
545 | ? impl.mCurlCode | ||
546 | : CURLE_OK; | ||
547 | } | ||
548 | |||
549 | return impl.mStatus; | ||
550 | } | ||
551 | |||
552 | std::string LLXMLRPCTransaction::statusMessage() | ||
553 | { | ||
554 | return impl.mStatusMessage; | ||
555 | } | ||
556 | |||
557 | std::string LLXMLRPCTransaction::statusURI() | ||
558 | { | ||
559 | return impl.mStatusURI; | ||
560 | } | ||
561 | |||
562 | XMLRPC_REQUEST LLXMLRPCTransaction::response() | ||
563 | { | ||
564 | return impl.mResponse; | ||
565 | } | ||
566 | |||
567 | LLXMLRPCValue LLXMLRPCTransaction::responseValue() | ||
568 | { | ||
569 | return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse)); | ||
570 | } | ||
571 | |||
572 | |||
573 | F64 LLXMLRPCTransaction::transferRate() | ||
574 | { | ||
575 | if (!impl.mCurl || impl.mStatus != StatusComplete) | ||
576 | { | ||
577 | return 0.0L; | ||
578 | } | ||
579 | |||
580 | double size_bytes = 0.0; | ||
581 | double time_seconds = 0.0; | ||
582 | double rate_bytes_per_sec = 0.0; | ||
583 | |||
584 | curl_easy_getinfo(impl.mCurl, CURLINFO_SIZE_DOWNLOAD, &size_bytes); | ||
585 | curl_easy_getinfo(impl.mCurl, CURLINFO_TOTAL_TIME, &time_seconds); | ||
586 | curl_easy_getinfo(impl.mCurl, CURLINFO_SPEED_DOWNLOAD, &rate_bytes_per_sec); | ||
587 | |||
588 | double rate_bits_per_sec = rate_bytes_per_sec * 8.0; | ||
589 | |||
590 | llinfos << "Buffer size: " << impl.mResponseText.size() << " B" << llendl; | ||
591 | llinfos << "Transfer size: " << size_bytes << " B" << llendl; | ||
592 | llinfos << "Transfer time: " << time_seconds << " s" << llendl; | ||
593 | llinfos << "Transfer rate: " << rate_bits_per_sec/1000.0 << " Kb/s" << llendl; | ||
594 | |||
595 | return rate_bits_per_sec; | ||
596 | } | ||