diff options
Diffstat (limited to 'indra/llcorehttp/_httplibcurl.cpp')
-rw-r--r-- | indra/llcorehttp/_httplibcurl.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/indra/llcorehttp/_httplibcurl.cpp b/indra/llcorehttp/_httplibcurl.cpp new file mode 100644 index 0000000000..15be977adf --- /dev/null +++ b/indra/llcorehttp/_httplibcurl.cpp @@ -0,0 +1,214 @@ +/** + * @file _httplibcurl.cpp + * @brief Internal definitions of the Http libcurl thread + * + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "_httplibcurl.h" + +#include "httpheaders.h" + +#include "_httpoprequest.h" +#include "_httpservice.h" + + +namespace LLCore +{ + + +HttpLibcurl::HttpLibcurl(HttpService * service) + : mService(service) +{ + mMultiHandles[0] = curl_multi_init(); +} + + +HttpLibcurl::~HttpLibcurl() +{ + // *FIXME: need to cancel requests in this class, not in op class. + while (! mActiveOps.empty()) + { + active_set_t::iterator item(mActiveOps.begin()); + + (*item)->cancel(); + (*item)->release(); + } + + if (mMultiHandles[0]) + { + // *FIXME: Do some multi cleanup here first + + + curl_multi_cleanup(mMultiHandles[0]); + mMultiHandles[0] = NULL; + } + + mService = NULL; +} + + +void HttpLibcurl::init() +{} + + +void HttpLibcurl::term() +{} + + +void HttpLibcurl::processTransport() +{ + if (mMultiHandles[0]) + { + // Give libcurl some cycles to do I/O & callbacks + int running(0); + CURLMcode status(CURLM_CALL_MULTI_PERFORM); + do + { + running = 0; + status = curl_multi_perform(mMultiHandles[0], &running); + } + while (0 != running && CURLM_CALL_MULTI_PERFORM == status); + + // Run completion on anything done + CURLMsg * msg(NULL); + int msgs_in_queue(0); + while ((msg = curl_multi_info_read(mMultiHandles[0], &msgs_in_queue))) + { + if (CURLMSG_DONE == msg->msg) + { + CURL * handle(msg->easy_handle); + CURLcode result(msg->data.result); + + completeRequest(mMultiHandles[0], handle, result); + handle = NULL; // No longer valid on return + } + else if (CURLMSG_NONE == msg->msg) + { + // Ignore this... it shouldn't mean anything. + ; + } + else + { + // *FIXME: Issue a logging event for this. + ; + } + msgs_in_queue = 0; + } + } +} + + +void HttpLibcurl::addOp(HttpOpRequest * op) +{ + // Create standard handle + if (! op->prepareForGet(mService)) + { + // Couldn't issue request, fail with notification + // *FIXME: Need failure path + return; + } + + // Make the request live + curl_multi_add_handle(mMultiHandles[0], op->mCurlHandle); + op->mCurlActive = true; + + // On success, make operation active + mActiveOps.insert(op); +} + + +void HttpLibcurl::completeRequest(CURLM * multi_handle, CURL * handle, CURLcode status) +{ + HttpOpRequest * op(NULL); + curl_easy_getinfo(handle, CURLINFO_PRIVATE, &op); + // *FIXME: check the pointer + + if (handle != op->mCurlHandle || ! op->mCurlActive) + { + // *FIXME: This is a sanity check that needs validation/termination. + ; + } + + active_set_t::iterator it(mActiveOps.find(op)); + if (mActiveOps.end() == it) + { + // *FIXME: Fatal condition. This must be here. + ; + } + else + { + mActiveOps.erase(it); + } + + // Deactivate request + op->mCurlActive = false; + + // Set final status of request + if (op->mStatus) + { + // Only set if it hasn't failed by other mechanisms yet + op->mStatus = HttpStatus(HttpStatus::EXT_CURL_EASY, status); + } + if (op->mStatus) + { + int http_status(200); + + curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &status); + op->mReplyStatus = http_status; + } + + // Detach from multi and recycle handle + curl_multi_remove_handle(multi_handle, handle); + curl_easy_cleanup(handle); + op->mCurlHandle = NULL; + + // Deliver to reply queue and release + op->stageFromActive(mService); + op->release(); +} + + +int HttpLibcurl::activeCount() const +{ + return mActiveOps.size(); +} + + +// --------------------------------------- +// Free functions +// --------------------------------------- + + +struct curl_slist * append_headers_to_slist(const HttpHeaders * headers, struct curl_slist * slist) +{ + for (HttpHeaders::container_t::const_iterator it(headers->mHeaders.begin()); + headers->mHeaders.end() != it; + ++it) + { + slist = curl_slist_append(slist, (*it).c_str()); + } + return slist; +} + + +} // end namespace LLCore |