00001
00034 #if LL_WINDOWS
00035 #define SAFE_SSL 1
00036 #elif LL_DARWIN
00037 #define SAFE_SSL 1
00038 #else
00039 #define SAFE_SSL 1
00040 #endif
00041
00042 #include "linden_common.h"
00043
00044 #include "llcurl.h"
00045
00046 #include <algorithm>
00047 #include <iomanip>
00048 #include <curl/curl.h>
00049 #if SAFE_SSL
00050 #include <openssl/crypto.h>
00051 #endif
00052
00053 #include "llbufferstream.h"
00054 #include "llstl.h"
00055 #include "llsdserialize.h"
00056 #include "llthread.h"
00057
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00075
00076 static const S32 EASY_HANDLE_POOL_SIZE = 5;
00077 static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
00078 static const S32 CURL_REQUEST_TIMEOUT = 30;
00079 static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
00080
00081
00082 S32 gCurlEasyCount = 0;
00083 S32 gCurlMultiCount = 0;
00084
00086
00087
00088 std::vector<LLMutex*> LLCurl::sSSLMutex;
00089 std::string LLCurl::sCAPath;
00090 std::string LLCurl::sCAFile;
00091
00092
00093 void LLCurl::setCAPath(const std::string& path)
00094 {
00095 sCAPath = path;
00096 }
00097
00098
00099 void LLCurl::setCAFile(const std::string& file)
00100 {
00101 sCAFile = file;
00102 }
00103
00105
00106 LLCurl::Responder::Responder()
00107 : mReferenceCount(0)
00108 {
00109 }
00110
00111 LLCurl::Responder::~Responder()
00112 {
00113 }
00114
00115
00116 void LLCurl::Responder::error(U32 status, const std::string& reason)
00117 {
00118 llinfos << status << ": " << reason << llendl;
00119 }
00120
00121
00122 void LLCurl::Responder::result(const LLSD& content)
00123 {
00124 }
00125
00126
00127 void LLCurl::Responder::completedRaw(U32 status, const std::string& reason,
00128 const LLChannelDescriptors& channels,
00129 const LLIOPipe::buffer_ptr_t& buffer)
00130 {
00131 if (isGoodStatus(status))
00132 {
00133 LLSD content;
00134 LLBufferStream istr(channels, buffer.get());
00135 LLSDSerialize::fromXML(content, istr);
00136
00137
00138
00139
00140
00141
00142
00143
00144 completed(status, reason, content);
00145 }
00146 else if (status == 400)
00147 {
00148
00149 char tbuf[4096];
00150 S32 len = 4096;
00151 buffer->readAfter(channels.in(), NULL, (U8*)tbuf, len);
00152 tbuf[len] = 0;
00153 completed(status, std::string(tbuf), LLSD());
00154 }
00155 else
00156 {
00157 completed(status, reason, LLSD());
00158 }
00159 }
00160
00161
00162 void LLCurl::Responder::completed(U32 status, const std::string& reason, const LLSD& content)
00163 {
00164 if (isGoodStatus(status))
00165 {
00166 result(content);
00167 }
00168 else
00169 {
00170
00171
00172
00173 error(status, reason);
00174 }
00175 }
00176
00177
00178 void LLCurl::Responder::completedHeader(U32 status, const std::string& reason, const LLSD& content)
00179 {
00180
00181 }
00182
00183 namespace boost
00184 {
00185 void intrusive_ptr_add_ref(LLCurl::Responder* p)
00186 {
00187 ++p->mReferenceCount;
00188 }
00189
00190 void intrusive_ptr_release(LLCurl::Responder* p)
00191 {
00192 if(p && 0 == --p->mReferenceCount)
00193 {
00194 delete p;
00195 }
00196 }
00197 };
00198
00199
00201
00202
00203 class LLCurl::Easy
00204 {
00205 LOG_CLASS(Easy);
00206
00207 private:
00208 Easy();
00209
00210 public:
00211 static Easy* getEasy();
00212 ~Easy();
00213
00214 CURL* getCurlHandle() const { return mCurlEasyHandle; }
00215
00216 void setErrorBuffer();
00217 void setCA();
00218
00219 void setopt(CURLoption option, S32 value);
00220
00221 void setopt(CURLoption option, void* value);
00222 void setopt(CURLoption option, char* value);
00223
00224 void setoptString(CURLoption option, const std::string& value);
00225
00226 void slist_append(const char* str);
00227 void setHeaders();
00228
00229 U32 report(CURLcode);
00230 void getTransferInfo(LLCurl::TransferInfo* info);
00231
00232 void prepRequest(const std::string& url, ResponderPtr, bool post = false);
00233
00234 const char* getErrorBuffer();
00235
00236 std::stringstream& getInput() { return mInput; }
00237 std::stringstream& getHeaderOutput() { return mHeaderOutput; }
00238 LLIOPipe::buffer_ptr_t& getOutput() { return mOutput; }
00239 const LLChannelDescriptors& getChannels() { return mChannels; }
00240
00241 void resetState();
00242
00243 private:
00244 CURL* mCurlEasyHandle;
00245 struct curl_slist* mHeaders;
00246
00247 std::stringstream mRequest;
00248 LLChannelDescriptors mChannels;
00249 LLIOPipe::buffer_ptr_t mOutput;
00250 std::stringstream mInput;
00251 std::stringstream mHeaderOutput;
00252 char mErrorBuffer[CURL_ERROR_SIZE];
00253
00254
00255 std::vector<char*> mStrings;
00256
00257 ResponderPtr mResponder;
00258 };
00259
00260 LLCurl::Easy::Easy()
00261 : mHeaders(NULL),
00262 mCurlEasyHandle(NULL)
00263 {
00264 mErrorBuffer[0] = 0;
00265 }
00266
00267 LLCurl::Easy* LLCurl::Easy::getEasy()
00268 {
00269 Easy* easy = new Easy();
00270 easy->mCurlEasyHandle = curl_easy_init();
00271 if (!easy->mCurlEasyHandle)
00272 {
00273
00274 llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
00275 delete easy;
00276 return NULL;
00277 }
00278 ++gCurlEasyCount;
00279 return easy;
00280 }
00281
00282 LLCurl::Easy::~Easy()
00283 {
00284 curl_easy_cleanup(mCurlEasyHandle);
00285 --gCurlEasyCount;
00286 curl_slist_free_all(mHeaders);
00287 for_each(mStrings.begin(), mStrings.end(), DeletePointer());
00288 }
00289
00290 void LLCurl::Easy::resetState()
00291 {
00292 curl_easy_reset(mCurlEasyHandle);
00293
00294 if (mHeaders)
00295 {
00296 curl_slist_free_all(mHeaders);
00297 mHeaders = NULL;
00298 }
00299
00300 mRequest.str("");
00301 mRequest.clear();
00302
00303 mOutput.reset();
00304
00305 mInput.str("");
00306 mInput.clear();
00307
00308 mErrorBuffer[0] = 0;
00309
00310 mHeaderOutput.str("");
00311 mHeaderOutput.clear();
00312 }
00313
00314 void LLCurl::Easy::setErrorBuffer()
00315 {
00316 setopt(CURLOPT_ERRORBUFFER, &mErrorBuffer);
00317 }
00318
00319 const char* LLCurl::Easy::getErrorBuffer()
00320 {
00321 return mErrorBuffer;
00322 }
00323
00324 void LLCurl::Easy::setCA()
00325 {
00326 if(!sCAPath.empty())
00327 {
00328 setoptString(CURLOPT_CAPATH, sCAPath);
00329 }
00330 if(!sCAFile.empty())
00331 {
00332 setoptString(CURLOPT_CAINFO, sCAFile);
00333 }
00334 }
00335
00336 void LLCurl::Easy::setHeaders()
00337 {
00338 setopt(CURLOPT_HTTPHEADER, mHeaders);
00339 }
00340
00341 void LLCurl::Easy::getTransferInfo(LLCurl::TransferInfo* info)
00342 {
00343 curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SIZE_DOWNLOAD, &info->mSizeDownload);
00344 curl_easy_getinfo(mCurlEasyHandle, CURLINFO_TOTAL_TIME, &info->mTotalTime);
00345 curl_easy_getinfo(mCurlEasyHandle, CURLINFO_SPEED_DOWNLOAD, &info->mSpeedDownload);
00346 }
00347
00348 U32 LLCurl::Easy::report(CURLcode code)
00349 {
00350 U32 responseCode = 0;
00351 std::string responseReason;
00352
00353 if (code == CURLE_OK)
00354 {
00355 curl_easy_getinfo(mCurlEasyHandle, CURLINFO_RESPONSE_CODE, &responseCode);
00356
00357 }
00358 else
00359 {
00360 responseCode = 499;
00361 responseReason = strerror(code) + " : " + mErrorBuffer;
00362 }
00363
00364 if (mResponder)
00365 {
00366 mResponder->completedRaw(responseCode, responseReason, mChannels, mOutput);
00367 mResponder = NULL;
00368 }
00369
00370 resetState();
00371 return responseCode;
00372 }
00373
00374
00375 void LLCurl::Easy::setopt(CURLoption option, S32 value)
00376 {
00377 curl_easy_setopt(mCurlEasyHandle, option, value);
00378 }
00379
00380 void LLCurl::Easy::setopt(CURLoption option, void* value)
00381 {
00382 curl_easy_setopt(mCurlEasyHandle, option, value);
00383 }
00384
00385 void LLCurl::Easy::setopt(CURLoption option, char* value)
00386 {
00387 curl_easy_setopt(mCurlEasyHandle, option, value);
00388 }
00389
00390
00391 void LLCurl::Easy::setoptString(CURLoption option, const std::string& value)
00392 {
00393 char* tstring = new char[value.length()+1];
00394 strcpy(tstring, value.c_str());
00395 mStrings.push_back(tstring);
00396 curl_easy_setopt(mCurlEasyHandle, option, tstring);
00397 }
00398
00399 void LLCurl::Easy::slist_append(const char* str)
00400 {
00401 mHeaders = curl_slist_append(mHeaders, str);
00402 }
00403
00404 size_t curlReadCallback(char* data, size_t size, size_t nmemb, void* user_data)
00405 {
00406 LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
00407
00408 S32 n = size * nmemb;
00409 S32 startpos = easy->getInput().tellg();
00410 easy->getInput().seekg(0, std::ios::end);
00411 S32 endpos = easy->getInput().tellg();
00412 easy->getInput().seekg(startpos, std::ios::beg);
00413 S32 maxn = endpos - startpos;
00414 n = llmin(n, maxn);
00415 easy->getInput().read((char*)data, n);
00416
00417 return n;
00418 }
00419
00420 size_t curlWriteCallback(char* data, size_t size, size_t nmemb, void* user_data)
00421 {
00422 LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
00423
00424 S32 n = size * nmemb;
00425 easy->getOutput()->append(easy->getChannels().in(), (const U8*)data, n);
00426
00427 return n;
00428 }
00429
00430 size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data)
00431 {
00432 LLCurl::Easy* easy = (LLCurl::Easy*)user_data;
00433
00434 size_t n = size * nmemb;
00435 easy->getHeaderOutput().write((const char*)data, n);
00436
00437 return n;
00438 }
00439
00440 void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, bool post)
00441 {
00442 resetState();
00443
00444 if (post) setoptString(CURLOPT_ENCODING, "");
00445
00446
00447 setopt(CURLOPT_NOSIGNAL, 1);
00448
00449 mOutput.reset(new LLBufferArray);
00450 setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
00451 setopt(CURLOPT_WRITEDATA, (void*)this);
00452
00453 setopt(CURLOPT_READFUNCTION, (void*)&curlReadCallback);
00454 setopt(CURLOPT_READDATA, (void*)this);
00455
00456 setopt(CURLOPT_HEADERFUNCTION, (void*)&curlHeaderCallback);
00457 setopt(CURLOPT_HEADERDATA, (void*)this);
00458
00459 setErrorBuffer();
00460 setCA();
00461
00462 setopt(CURLOPT_SSL_VERIFYPEER, true);
00463 setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
00464
00465 setoptString(CURLOPT_URL, url);
00466
00467 mResponder = responder;
00468
00469 if (!post)
00470 {
00471 slist_append("Connection: keep-alive");
00472 slist_append("Keep-alive: 300");
00473 }
00474
00475 }
00476
00478
00479 class LLCurl::Multi
00480 {
00481 LOG_CLASS(Multi);
00482 public:
00483
00484 Multi();
00485 ~Multi();
00486
00487 Easy* allocEasy();
00488 bool addEasy(Easy* easy);
00489
00490 void removeEasy(Easy* easy);
00491
00492 S32 process();
00493 S32 perform();
00494
00495 CURLMsg* info_read(S32* msgs_in_queue);
00496
00497 S32 mQueued;
00498 S32 mErrorCount;
00499
00500 private:
00501 void easyFree(Easy*);
00502
00503 CURLM* mCurlMultiHandle;
00504
00505 typedef std::set<Easy*> easy_active_list_t;
00506 easy_active_list_t mEasyActiveList;
00507 typedef std::map<CURL*, Easy*> easy_active_map_t;
00508 easy_active_map_t mEasyActiveMap;
00509 typedef std::set<Easy*> easy_free_list_t;
00510 easy_free_list_t mEasyFreeList;
00511 };
00512
00513 LLCurl::Multi::Multi()
00514 : mQueued(0),
00515 mErrorCount(0)
00516 {
00517 mCurlMultiHandle = curl_multi_init();
00518 if (!mCurlMultiHandle)
00519 {
00520 llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
00521 mCurlMultiHandle = curl_multi_init();
00522 }
00523 llassert_always(mCurlMultiHandle);
00524 ++gCurlMultiCount;
00525 }
00526
00527 LLCurl::Multi::~Multi()
00528 {
00529
00530 for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
00531 iter != mEasyActiveList.end(); ++iter)
00532 {
00533 Easy* easy = *iter;
00534 curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
00535 delete easy;
00536 }
00537 mEasyActiveList.clear();
00538 mEasyActiveMap.clear();
00539
00540
00541 for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
00542 mEasyFreeList.clear();
00543
00544 curl_multi_cleanup(mCurlMultiHandle);
00545 --gCurlMultiCount;
00546 }
00547
00548 CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
00549 {
00550 CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue);
00551 return curlmsg;
00552 }
00553
00554
00555 S32 LLCurl::Multi::perform()
00556 {
00557 S32 q = 0;
00558 for (S32 call_count = 0;
00559 call_count < MULTI_PERFORM_CALL_REPEAT;
00560 call_count += 1)
00561 {
00562 CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
00563 if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
00564 {
00565 break;
00566 }
00567 }
00568 mQueued = q;
00569 return q;
00570 }
00571
00572 S32 LLCurl::Multi::process()
00573 {
00574 perform();
00575
00576 CURLMsg* msg;
00577 int msgs_in_queue;
00578
00579 S32 processed = 0;
00580 while ((msg = info_read(&msgs_in_queue)))
00581 {
00582 ++processed;
00583 if (msg->msg == CURLMSG_DONE)
00584 {
00585 U32 response = 0;
00586 easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle);
00587 if (iter != mEasyActiveMap.end())
00588 {
00589 Easy* easy = iter->second;
00590 response = easy->report(msg->data.result);
00591 removeEasy(easy);
00592 }
00593 else
00594 {
00595 response = 499;
00596
00597 llerrs << "cleaned up curl request completed!" << llendl;
00598 }
00599 if (response >= 400)
00600 {
00601
00602 ++mErrorCount;
00603 }
00604 }
00605 }
00606 return processed;
00607 }
00608
00609 LLCurl::Easy* LLCurl::Multi::allocEasy()
00610 {
00611 Easy* easy = 0;
00612
00613 if (mEasyFreeList.empty())
00614 {
00615 easy = Easy::getEasy();
00616 }
00617 else
00618 {
00619 easy = *(mEasyFreeList.begin());
00620 mEasyFreeList.erase(easy);
00621 }
00622 if (easy)
00623 {
00624 mEasyActiveList.insert(easy);
00625 mEasyActiveMap[easy->getCurlHandle()] = easy;
00626 }
00627 return easy;
00628 }
00629
00630 bool LLCurl::Multi::addEasy(Easy* easy)
00631 {
00632 CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
00633 if (mcode != CURLM_OK)
00634 {
00635 llwarns << "Curl Error: " << curl_multi_strerror(mcode) << llendl;
00636 return false;
00637 }
00638 return true;
00639 }
00640
00641 void LLCurl::Multi::easyFree(Easy* easy)
00642 {
00643 mEasyActiveList.erase(easy);
00644 mEasyActiveMap.erase(easy->getCurlHandle());
00645 if (mEasyFreeList.size() < EASY_HANDLE_POOL_SIZE)
00646 {
00647 easy->resetState();
00648 mEasyFreeList.insert(easy);
00649 }
00650 else
00651 {
00652 delete easy;
00653 }
00654 }
00655
00656 void LLCurl::Multi::removeEasy(Easy* easy)
00657 {
00658 curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle());
00659 easyFree(easy);
00660 }
00661
00662
00663 std::string LLCurl::strerror(CURLcode errorcode)
00664 {
00665 #if LL_DARWIN
00666
00667
00668
00669
00670 return llformat("%d", errorcode);
00671 #else // LL_DARWIN
00672 return std::string(curl_easy_strerror(errorcode));
00673 #endif // LL_DARWIN
00674 }
00675
00677
00678
00679
00680 LLCurlRequest::LLCurlRequest() :
00681 mActiveMulti(NULL),
00682 mActiveRequestCount(0)
00683 {
00684 }
00685
00686 LLCurlRequest::~LLCurlRequest()
00687 {
00688 for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
00689 }
00690
00691 void LLCurlRequest::addMulti()
00692 {
00693 LLCurl::Multi* multi = new LLCurl::Multi();
00694 mMultiSet.insert(multi);
00695 mActiveMulti = multi;
00696 mActiveRequestCount = 0;
00697 }
00698
00699 LLCurl::Easy* LLCurlRequest::allocEasy()
00700 {
00701 if (!mActiveMulti ||
00702 mActiveRequestCount >= MAX_ACTIVE_REQUEST_COUNT ||
00703 mActiveMulti->mErrorCount > 0)
00704 {
00705 addMulti();
00706 }
00707 llassert_always(mActiveMulti);
00708 ++mActiveRequestCount;
00709 LLCurl::Easy* easy = mActiveMulti->allocEasy();
00710 return easy;
00711 }
00712
00713 bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
00714 {
00715 llassert_always(mActiveMulti);
00716 bool res = mActiveMulti->addEasy(easy);
00717 return res;
00718 }
00719
00720 void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
00721 {
00722 getByteRange(url, 0, -1, responder);
00723 }
00724
00725 bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length, LLCurl::ResponderPtr responder)
00726 {
00727 LLCurl::Easy* easy = allocEasy();
00728 if (!easy)
00729 {
00730 return false;
00731 }
00732 easy->prepRequest(url, responder);
00733 easy->setopt(CURLOPT_HTTPGET, 1);
00734 if (length > 0)
00735 {
00736 std::string range = llformat("Range: bytes=%d-%d", offset,offset+length-1);
00737 easy->slist_append(range.c_str());
00738 }
00739 easy->setHeaders();
00740 bool res = addEasy(easy);
00741 return res;
00742 }
00743
00744 bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::ResponderPtr responder)
00745 {
00746 LLCurl::Easy* easy = allocEasy();
00747 if (!easy)
00748 {
00749 return false;
00750 }
00751 easy->prepRequest(url, responder);
00752
00753 LLSDSerialize::toXML(data, easy->getInput());
00754 S32 bytes = easy->getInput().str().length();
00755
00756 easy->setopt(CURLOPT_POST, 1);
00757 easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
00758 easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
00759
00760 easy->slist_append("Content-Type: application/xml");
00761 easy->setHeaders();
00762
00763 lldebugs << "POSTING: " << bytes << " bytes." << llendl;
00764 bool res = addEasy(easy);
00765 return res;
00766 }
00767
00768
00769 S32 LLCurlRequest::process()
00770 {
00771 S32 res = 0;
00772 for (curlmulti_set_t::iterator iter = mMultiSet.begin();
00773 iter != mMultiSet.end(); )
00774 {
00775 curlmulti_set_t::iterator curiter = iter++;
00776 LLCurl::Multi* multi = *curiter;
00777 S32 tres = multi->process();
00778 res += tres;
00779 if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
00780 {
00781 mMultiSet.erase(curiter);
00782 delete multi;
00783 }
00784 }
00785 return res;
00786 }
00787
00788 S32 LLCurlRequest::getQueued()
00789 {
00790 S32 queued = 0;
00791 for (curlmulti_set_t::iterator iter = mMultiSet.begin();
00792 iter != mMultiSet.end(); )
00793 {
00794 curlmulti_set_t::iterator curiter = iter++;
00795 LLCurl::Multi* multi = *curiter;
00796 queued += multi->mQueued;
00797 }
00798 return queued;
00799 }
00800
00802
00803
00804
00805 LLCurlEasyRequest::LLCurlEasyRequest()
00806 : mRequestSent(false),
00807 mResultReturned(false)
00808 {
00809 mMulti = new LLCurl::Multi();
00810 mEasy = mMulti->allocEasy();
00811 if (mEasy)
00812 {
00813 mEasy->setErrorBuffer();
00814 mEasy->setCA();
00815 }
00816 }
00817
00818 LLCurlEasyRequest::~LLCurlEasyRequest()
00819 {
00820 delete mMulti;
00821 }
00822
00823 void LLCurlEasyRequest::setopt(CURLoption option, S32 value)
00824 {
00825 if (mEasy)
00826 {
00827 mEasy->setopt(option, value);
00828 }
00829 }
00830
00831 void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value)
00832 {
00833 if (mEasy)
00834 {
00835 mEasy->setoptString(option, value);
00836 }
00837 }
00838
00839 void LLCurlEasyRequest::setPost(char* postdata, S32 size)
00840 {
00841 if (mEasy)
00842 {
00843 mEasy->setopt(CURLOPT_POST, 1);
00844 mEasy->setopt(CURLOPT_POSTFIELDS, postdata);
00845 mEasy->setopt(CURLOPT_POSTFIELDSIZE, size);
00846 }
00847 }
00848
00849 void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata)
00850 {
00851 if (mEasy)
00852 {
00853 mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback);
00854 mEasy->setopt(CURLOPT_HEADERDATA, userdata);
00855 }
00856 }
00857
00858 void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata)
00859 {
00860 if (mEasy)
00861 {
00862 mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback);
00863 mEasy->setopt(CURLOPT_WRITEDATA, userdata);
00864 }
00865 }
00866
00867 void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata)
00868 {
00869 if (mEasy)
00870 {
00871 mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback);
00872 mEasy->setopt(CURLOPT_READDATA, userdata);
00873 }
00874 }
00875
00876 void LLCurlEasyRequest::slist_append(const char* str)
00877 {
00878 if (mEasy)
00879 {
00880 mEasy->slist_append(str);
00881 }
00882 }
00883
00884 void LLCurlEasyRequest::sendRequest(const std::string& url)
00885 {
00886 llassert_always(!mRequestSent);
00887 mRequestSent = true;
00888 lldebugs << url << llendl;
00889 if (mEasy)
00890 {
00891 mEasy->setHeaders();
00892 mEasy->setoptString(CURLOPT_URL, url);
00893 mMulti->addEasy(mEasy);
00894 }
00895 }
00896
00897 void LLCurlEasyRequest::requestComplete()
00898 {
00899 llassert_always(mRequestSent);
00900 mRequestSent = false;
00901 if (mEasy)
00902 {
00903 mMulti->removeEasy(mEasy);
00904 }
00905 }
00906
00907 S32 LLCurlEasyRequest::perform()
00908 {
00909 return mMulti->perform();
00910 }
00911
00912
00913 bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
00914 {
00915 if (!mEasy)
00916 {
00917
00918
00919 if (mResultReturned)
00920 {
00921 return false;
00922 }
00923 else
00924 {
00925 *result = CURLE_FAILED_INIT;
00926 mResultReturned = true;
00927 return true;
00928 }
00929 }
00930
00931
00932
00933 while(1)
00934 {
00935 S32 q;
00936 CURLMsg* curlmsg = info_read(&q, info);
00937 if (curlmsg)
00938 {
00939 if (curlmsg->msg == CURLMSG_DONE)
00940 {
00941 *result = curlmsg->data.result;
00942 return true;
00943 }
00944
00945 }
00946 else
00947 {
00948 return false;
00949 }
00950 }
00951 }
00952
00953
00954 CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info)
00955 {
00956 if (mEasy)
00957 {
00958 CURLMsg* curlmsg = mMulti->info_read(q);
00959 if (curlmsg && curlmsg->msg == CURLMSG_DONE)
00960 {
00961 if (info)
00962 {
00963 mEasy->getTransferInfo(info);
00964 }
00965 }
00966 return curlmsg;
00967 }
00968 return NULL;
00969 }
00970
00971 std::string LLCurlEasyRequest::getErrorString()
00972 {
00973 return mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();
00974 }
00975
00977
00978 #if SAFE_SSL
00979
00980 void LLCurl::ssl_locking_callback(int mode, int type, const char *file, int line)
00981 {
00982 if (mode & CRYPTO_LOCK)
00983 {
00984 LLCurl::sSSLMutex[type]->lock();
00985 }
00986 else
00987 {
00988 LLCurl::sSSLMutex[type]->unlock();
00989 }
00990 }
00991
00992
00993 unsigned long LLCurl::ssl_thread_id(void)
00994 {
00995 return LLThread::currentID();
00996 }
00997 #endif
00998
00999 void LLCurl::initClass()
01000 {
01001
01002
01003
01004 curl_global_init(CURL_GLOBAL_ALL);
01005
01006 #if SAFE_SSL
01007 S32 mutex_count = CRYPTO_num_locks();
01008 for (S32 i=0; i<mutex_count; i++)
01009 {
01010 sSSLMutex.push_back(new LLMutex(gAPRPoolp));
01011 }
01012 CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
01013 CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
01014 #endif
01015 }
01016
01017 void LLCurl::cleanupClass()
01018 {
01019 #if SAFE_SSL
01020 CRYPTO_set_locking_callback(NULL);
01021 for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
01022 #endif
01023 curl_global_cleanup();
01024 }
01025