aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llxmlrpctransaction.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llxmlrpctransaction.cpp
parentREADME.txt (diff)
downloadmeta-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.cpp596
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
40LLXMLRPCValue LLXMLRPCValue::operator[](const char* id) const
41{
42 return LLXMLRPCValue(XMLRPC_VectorGetValueWithID(mV, id));
43}
44
45std::string LLXMLRPCValue::asString() const
46{
47 const char* s = XMLRPC_GetValueString(mV);
48 return s ? s : "";
49}
50
51int LLXMLRPCValue::asInt() const { return XMLRPC_GetValueInt(mV); }
52bool LLXMLRPCValue::asBool() const { return XMLRPC_GetValueBoolean(mV) != 0; }
53double LLXMLRPCValue::asDouble() const { return XMLRPC_GetValueDouble(mV); }
54
55LLXMLRPCValue LLXMLRPCValue::rewind()
56{
57 return LLXMLRPCValue(XMLRPC_VectorRewind(mV));
58}
59
60LLXMLRPCValue LLXMLRPCValue::next()
61{
62 return LLXMLRPCValue(XMLRPC_VectorNext(mV));
63}
64
65bool LLXMLRPCValue::isValid() const
66{
67 return mV != NULL;
68}
69
70LLXMLRPCValue LLXMLRPCValue::createArray()
71{
72 return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_array));
73}
74
75LLXMLRPCValue LLXMLRPCValue::createStruct()
76{
77 return LLXMLRPCValue(XMLRPC_CreateVector(NULL, xmlrpc_vector_struct));
78}
79
80
81void LLXMLRPCValue::append(LLXMLRPCValue& v)
82{
83 XMLRPC_AddValueToVector(mV, v.mV);
84}
85
86void LLXMLRPCValue::appendString(const std::string& v)
87{
88 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(NULL, v.c_str(), 0));
89}
90
91void LLXMLRPCValue::appendInt(int v)
92{
93 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(NULL, v));
94}
95
96void LLXMLRPCValue::appendBool(bool v)
97{
98 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(NULL, v));
99}
100
101void LLXMLRPCValue::appendDouble(double v)
102{
103 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(NULL, v));
104}
105
106
107void LLXMLRPCValue::append(const char* id, LLXMLRPCValue& v)
108{
109 XMLRPC_SetValueID(v.mV, id, 0);
110 XMLRPC_AddValueToVector(mV, v.mV);
111}
112
113void LLXMLRPCValue::appendString(const char* id, const std::string& v)
114{
115 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueString(id, v.c_str(), 0));
116}
117
118void LLXMLRPCValue::appendInt(const char* id, int v)
119{
120 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueInt(id, v));
121}
122
123void LLXMLRPCValue::appendBool(const char* id, bool v)
124{
125 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueBoolean(id, v));
126}
127
128void LLXMLRPCValue::appendDouble(const char* id, double v)
129{
130 XMLRPC_AddValueToVector(mV, XMLRPC_CreateValueDouble(id, v));
131}
132
133void LLXMLRPCValue::free()
134{
135 XMLRPC_CleanupValue(mV);
136 mV = NULL;
137}
138
139XMLRPC_VALUE LLXMLRPCValue::getValue() const
140{
141 return mV;
142}
143
144
145class LLXMLRPCTransaction::Impl
146{
147public:
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
181private:
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
188LLXMLRPCTransaction::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
200LLXMLRPCTransaction::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
219void 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
270LLXMLRPCTransaction::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
303bool 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
397void 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
456void 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
499size_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
517LLXMLRPCTransaction::LLXMLRPCTransaction(
518 const std::string& uri, XMLRPC_REQUEST request, bool useGzip)
519: impl(* new Impl(uri, request, useGzip))
520{ }
521
522
523LLXMLRPCTransaction::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
529LLXMLRPCTransaction::~LLXMLRPCTransaction()
530{
531 delete &impl;
532}
533
534bool LLXMLRPCTransaction::process()
535{
536 return impl.process();
537}
538
539LLXMLRPCTransaction::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
552std::string LLXMLRPCTransaction::statusMessage()
553{
554 return impl.mStatusMessage;
555}
556
557std::string LLXMLRPCTransaction::statusURI()
558{
559 return impl.mStatusURI;
560}
561
562XMLRPC_REQUEST LLXMLRPCTransaction::response()
563{
564 return impl.mResponse;
565}
566
567LLXMLRPCValue LLXMLRPCTransaction::responseValue()
568{
569 return LLXMLRPCValue(XMLRPC_RequestGetData(impl.mResponse));
570}
571
572
573F64 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}