summaryrefslogtreecommitdiff
path: root/indra/llmessage
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage')
-rw-r--r--indra/llmessage/llares.cpp17
-rw-r--r--indra/llmessage/llassetstorage.cpp30
-rw-r--r--indra/llmessage/llbuffer.cpp90
-rw-r--r--indra/llmessage/llbuffer.h25
-rw-r--r--indra/llmessage/llbufferstream.cpp8
-rw-r--r--indra/llmessage/llcurl.cpp688
-rw-r--r--[-rwxr-xr-x]indra/llmessage/llcurl.h137
-rw-r--r--indra/llmessage/llhttpassetstorage.cpp10
-rw-r--r--indra/llmessage/llhttpclient.cpp12
-rw-r--r--indra/llmessage/lliohttpserver.cpp14
-rw-r--r--indra/llmessage/lliohttpserver.h2
-rw-r--r--indra/llmessage/lliopipe.cpp6
-rw-r--r--indra/llmessage/lliopipe.h2
-rw-r--r--indra/llmessage/lliosocket.cpp102
-rw-r--r--indra/llmessage/lliosocket.h37
-rw-r--r--indra/llmessage/llmail.cpp17
-rw-r--r--indra/llmessage/llmail.h4
-rw-r--r--indra/llmessage/llproxy.cpp4
-rw-r--r--indra/llmessage/llpumpio.cpp121
-rw-r--r--indra/llmessage/llpumpio.h44
-rw-r--r--indra/llmessage/llsdmessagereader.cpp3
-rw-r--r--indra/llmessage/llsdrpcclient.h22
-rw-r--r--indra/llmessage/llurlrequest.cpp61
-rw-r--r--indra/llmessage/llurlrequest.h2
-rw-r--r--indra/llmessage/message.cpp17
-rw-r--r--indra/llmessage/tests/networkio.h9
26 files changed, 1110 insertions, 374 deletions
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index fab9858b69..5a67035ed1 100644
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -28,7 +28,6 @@
#include "linden_common.h"
#include "llares.h"
-#include "llscopedvolatileaprpool.h"
#include <ares_dns.h>
#include <ares_version.h>
@@ -465,6 +464,11 @@ void LLAres::search(const std::string &query, LLResType type,
bool LLAres::process(U64 timeout)
{
+ if (!gAPRPoolp)
+ {
+ ll_init_apr();
+ }
+
ares_socket_t socks[ARES_GETSOCK_MAXNUM];
apr_pollfd_t aprFds[ARES_GETSOCK_MAXNUM];
apr_int32_t nsds = 0;
@@ -478,7 +482,10 @@ bool LLAres::process(U64 timeout)
return nsds > 0;
}
- LLScopedVolatileAPRPool scoped_pool;
+ apr_status_t status;
+ LLAPRPool pool;
+ status = pool.getStatus() ;
+ ll_apr_assert_status(status);
for (int i = 0; i < ARES_GETSOCK_MAXNUM; i++)
{
@@ -495,7 +502,7 @@ bool LLAres::process(U64 timeout)
apr_socket_t *aprSock = NULL;
- apr_status_t status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], scoped_pool);
+ status = apr_os_sock_put(&aprSock, (apr_os_sock_t *) &socks[i], pool.getAPRPool());
if (status != APR_SUCCESS)
{
ll_apr_warn_status(status);
@@ -504,7 +511,7 @@ bool LLAres::process(U64 timeout)
aprFds[nactive].desc.s = aprSock;
aprFds[nactive].desc_type = APR_POLL_SOCKET;
- aprFds[nactive].p = scoped_pool;
+ aprFds[nactive].p = pool.getAPRPool();
aprFds[nactive].rtnevents = 0;
aprFds[nactive].client_data = &socks[i];
@@ -513,7 +520,7 @@ bool LLAres::process(U64 timeout)
if (nactive > 0)
{
- apr_status_t status = apr_poll(aprFds, nactive, &nsds, timeout);
+ status = apr_poll(aprFds, nactive, &nsds, timeout);
if (status != APR_SUCCESS && status != APR_TIMEUP)
{
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 31cdb1219b..9b86daebe5 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -149,8 +149,8 @@ void LLAssetInfo::setFromNameValue( const LLNameValue& nv )
setName( buf );
buf.assign( str, pos2, std::string::npos );
setDescription( buf );
- llinfos << "uuid: " << mUuid << llendl;
- llinfos << "creator: " << mCreatorID << llendl;
+ LL_DEBUGS("AssetStorage") << "uuid: " << mUuid << llendl;
+ LL_DEBUGS("AssetStorage") << "creator: " << mCreatorID << llendl;
}
///----------------------------------------------------------------------------
@@ -434,9 +434,9 @@ bool LLAssetStorage::findInStaticVFSAndInvokeCallback(const LLUUID& uuid, LLAsse
// IW - uuid is passed by value to avoid side effects, please don't re-add &
void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LLGetAssetCallback callback, void *user_data, BOOL is_priority)
{
- lldebugs << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
+ LL_DEBUGS("AssetStorage") << "LLAssetStorage::getAssetData() - " << uuid << "," << LLAssetType::lookup(type) << llendl;
- llinfos << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;
+ LL_DEBUGS("AssetStorage") << "ASSET_TRACE requesting " << uuid << " type " << LLAssetType::lookup(type) << llendl;
if (user_data)
{
@@ -446,7 +446,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
if (mShutDown)
{
- llinfos << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;
+ LL_DEBUGS("AssetStorage") << "ASSET_TRACE cancelled " << uuid << " type " << LLAssetType::lookup(type) << " shutting down" << llendl;
if (callback)
{
@@ -468,7 +468,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
// Try static VFS first.
if (findInStaticVFSAndInvokeCallback(uuid,type,callback,user_data))
{
- llinfos << "ASSET_TRACE asset " << uuid << " found in static VFS" << llendl;
+ LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in static VFS" << llendl;
return;
}
@@ -486,7 +486,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
callback(mVFS, uuid, type, user_data, LL_ERR_NOERR, LL_EXSTAT_VFS_CACHED);
}
- llinfos << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
+ LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << uuid << " found in VFS" << llendl;
}
else
{
@@ -520,7 +520,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, LL
}
if (duplicate)
{
- llinfos << "Adding additional non-duplicate request for asset " << uuid
+ LL_DEBUGS("AssetStorage") << "Adding additional non-duplicate request for asset " << uuid
<< "." << LLAssetType::lookup(type) << llendl;
}
@@ -584,9 +584,9 @@ void LLAssetStorage::downloadCompleteCallback(
LLAssetType::EType file_type,
void* user_data, LLExtStat ext_status)
{
- llinfos << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << llendl;
+ LL_DEBUGS("AssetStorage") << "ASSET_TRACE asset " << file_id << " downloadCompleteCallback" << llendl;
- lldebugs << "LLAssetStorage::downloadCompleteCallback() for " << file_id
+ LL_DEBUGS("AssetStorage") << "LLAssetStorage::downloadCompleteCallback() for " << file_id
<< "," << LLAssetType::lookup(file_type) << llendl;
LLAssetRequest* req = (LLAssetRequest*)user_data;
if(!req)
@@ -731,7 +731,7 @@ void LLAssetStorage::getEstateAsset(const LLHost &object_sim, const LLUUID &agen
tpvf.setAsset(asset_id, atype);
tpvf.setCallback(downloadEstateAssetCompleteCallback, req);
- llinfos << "Starting transfer for " << asset_id << llendl;
+ LL_DEBUGS("AssetStorage") << "Starting transfer for " << asset_id << llendl;
LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
ttcp->requestTransfer(spe, tpvf, 100.f + (is_priority ? 1.f : 0.f));
}
@@ -871,7 +871,7 @@ void LLAssetStorage::getInvItemAsset(const LLHost &object_sim, const LLUUID &age
tpvf.setAsset(asset_id, atype);
tpvf.setCallback(downloadInvItemCompleteCallback, req);
- llinfos << "Starting transfer for inventory asset "
+ LL_DEBUGS("AssetStorage") << "Starting transfer for inventory asset "
<< item_id << " owned by " << owner_id << "," << task_id
<< llendl;
LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(source_host, LLTCT_ASSET);
@@ -1211,7 +1211,7 @@ bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt,
request_list_t* requests = getRequestList(rt);
if (deletePendingRequestImpl(requests, asset_type, asset_id))
{
- llinfos << "Asset " << getRequestName(rt) << " request for "
+ LL_DEBUGS("AssetStorage") << "Asset " << getRequestName(rt) << " request for "
<< asset_id << "." << LLAssetType::lookup(asset_type)
<< " removed from pending queue." << llendl;
return true;
@@ -1307,7 +1307,7 @@ void LLAssetStorage::getAssetData(const LLUUID uuid, LLAssetType::EType type, vo
user_data == ((LLLegacyAssetRequest *)tmp->mUserData)->mUserData)
{
// this is a duplicate from the same subsystem - throw it away
- llinfos << "Discarding duplicate request for UUID " << uuid << llendl;
+ LL_DEBUGS("AssetStorage") << "Discarding duplicate request for UUID " << uuid << llendl;
return;
}
}
@@ -1490,7 +1490,7 @@ void LLAssetStorage::reportMetric( const LLUUID& asset_id, const LLAssetType::ET
{
if( !metric_recipient )
{
- llinfos << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << llendl;
+ LL_DEBUGS("AssetStorage") << "Couldn't store LLAssetStoreage::reportMetric - no metrics_recipient" << llendl;
return;
}
diff --git a/indra/llmessage/llbuffer.cpp b/indra/llmessage/llbuffer.cpp
index 0316797f00..250cace6e9 100644
--- a/indra/llmessage/llbuffer.cpp
+++ b/indra/llmessage/llbuffer.cpp
@@ -32,6 +32,9 @@
#include "llmath.h"
#include "llmemtype.h"
#include "llstl.h"
+#include "llthread.h"
+
+#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked());
/**
* LLSegment
@@ -224,7 +227,8 @@ void LLHeapBuffer::allocate(S32 size)
* LLBufferArray
*/
LLBufferArray::LLBufferArray() :
- mNextBaseChannel(0)
+ mNextBaseChannel(0),
+ mMutexp(NULL)
{
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
}
@@ -233,6 +237,8 @@ LLBufferArray::~LLBufferArray()
{
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer());
+
+ delete mMutexp;
}
// static
@@ -243,14 +249,57 @@ LLChannelDescriptors LLBufferArray::makeChannelConsumer(
return rv;
}
+void LLBufferArray::lock()
+{
+ if(mMutexp)
+ {
+ mMutexp->lock() ;
+ }
+}
+
+void LLBufferArray::unlock()
+{
+ if(mMutexp)
+ {
+ mMutexp->unlock() ;
+ }
+}
+
+LLMutex* LLBufferArray::getMutex()
+{
+ return mMutexp ;
+}
+
+void LLBufferArray::setThreaded(bool threaded)
+{
+ if(threaded)
+ {
+ if(!mMutexp)
+ {
+ mMutexp = new LLMutex(NULL);
+ }
+ }
+ else
+ {
+ if(mMutexp)
+ {
+ delete mMutexp ;
+ mMutexp = NULL ;
+ }
+ }
+}
+
LLChannelDescriptors LLBufferArray::nextChannel()
{
LLChannelDescriptors rv(mNextBaseChannel++);
return rv;
}
+//mMutexp should be locked before calling this.
S32 LLBufferArray::capacity() const
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
+
S32 total = 0;
const_buffer_iterator_t iter = mBuffers.begin();
const_buffer_iterator_t end = mBuffers.end();
@@ -263,6 +312,8 @@ S32 LLBufferArray::capacity() const
bool LLBufferArray::append(S32 channel, const U8* src, S32 len)
{
+ LLMutexLock lock(mMutexp) ;
+
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
std::vector<LLSegment> segments;
if(copyIntoBuffers(channel, src, len, segments))
@@ -273,8 +324,11 @@ bool LLBufferArray::append(S32 channel, const U8* src, S32 len)
return false;
}
+//mMutexp should be locked before calling this.
bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
+
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
std::vector<LLSegment> segments;
if(copyIntoBuffers(channel, src, len, segments))
@@ -293,6 +347,8 @@ bool LLBufferArray::insertAfter(
{
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
std::vector<LLSegment> segments;
+
+ LLMutexLock lock(mMutexp) ;
if(mSegments.end() != segment)
{
++segment;
@@ -305,8 +361,11 @@ bool LLBufferArray::insertAfter(
return false;
}
+//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
+
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
segment_iterator_t end = mSegments.end();
segment_iterator_t it = getSegment(address);
@@ -335,20 +394,26 @@ LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)
return rv;
}
+//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::beginSegment()
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
return mSegments.begin();
}
+//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::endSegment()
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
return mSegments.end();
}
+//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(
U8* address,
LLSegment& segment)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
segment_iterator_t rv = mSegments.begin();
segment_iterator_t end = mSegments.end();
@@ -395,8 +460,10 @@ LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(
return rv;
}
+//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
segment_iterator_t end = mSegments.end();
if(!address)
{
@@ -414,9 +481,11 @@ LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)
return end;
}
+//mMutexp should be locked before calling this.
LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment(
U8* address) const
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
const_segment_iterator_t end = mSegments.end();
if(!address)
{
@@ -466,6 +535,8 @@ S32 LLBufferArray::countAfter(S32 channel, U8* start) const
S32 count = 0;
S32 offset = 0;
const_segment_iterator_t it;
+
+ LLMutexLock lock(mMutexp) ;
const_segment_iterator_t end = mSegments.end();
if(start)
{
@@ -517,6 +588,8 @@ U8* LLBufferArray::readAfter(
len = 0;
S32 bytes_to_copy = 0;
const_segment_iterator_t it;
+
+ LLMutexLock lock(mMutexp) ;
const_segment_iterator_t end = mSegments.end();
if(start)
{
@@ -568,6 +641,7 @@ U8* LLBufferArray::seek(
U8* start,
S32 delta) const
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
const_segment_iterator_t it;
const_segment_iterator_t end = mSegments.end();
@@ -709,9 +783,14 @@ U8* LLBufferArray::seek(
return rv;
}
+//test use only
bool LLBufferArray::takeContents(LLBufferArray& source)
{
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
+
+ LLMutexLock lock(mMutexp);
+ source.lock();
+
std::copy(
source.mBuffers.begin(),
source.mBuffers.end(),
@@ -723,13 +802,17 @@ bool LLBufferArray::takeContents(LLBufferArray& source)
std::back_insert_iterator<segment_list_t>(mSegments));
source.mSegments.clear();
source.mNextBaseChannel = 0;
+ source.unlock();
+
return true;
}
+//mMutexp should be locked before calling this.
LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(
S32 channel,
S32 len)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
// start at the end of the buffers, because it is the most likely
// to have free space.
@@ -765,8 +848,10 @@ LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(
return send;
}
+//mMutexp should be locked before calling this.
bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
// Find out which buffer contains the segment, and if it is found,
@@ -792,13 +877,14 @@ bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)
return rv;
}
-
+//mMutexp should be locked before calling this.
bool LLBufferArray::copyIntoBuffers(
S32 channel,
const U8* src,
S32 len,
std::vector<LLSegment>& segments)
{
+ ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
if(!src || !len) return false;
S32 copied = 0;
diff --git a/indra/llmessage/llbuffer.h b/indra/llmessage/llbuffer.h
index 1c42b6fbc6..ccdb9fa7ee 100644
--- a/indra/llmessage/llbuffer.h
+++ b/indra/llmessage/llbuffer.h
@@ -39,6 +39,7 @@
#include <list>
#include <vector>
+class LLMutex;
/**
* @class LLChannelDescriptors
* @brief A way simple interface to accesss channels inside a buffer
@@ -564,6 +565,29 @@ public:
* @return Returns true on success.
*/
bool eraseSegment(const segment_iterator_t& iter);
+
+ /**
+ * @brief Lock the mutex if it exists
+ * This method locks mMutexp to make accessing LLBufferArray thread-safe
+ */
+ void lock();
+
+ /**
+ * @brief Unlock the mutex if it exists
+ */
+ void unlock();
+
+ /**
+ * @brief Return mMutexp
+ */
+ LLMutex* getMutex();
+
+ /**
+ * @brief Set LLBufferArray to be shared across threads or not
+ * This method is to create mMutexp if is threaded.
+ * @param threaded Indicates this LLBufferArray instance is shared across threads if true.
+ */
+ void setThreaded(bool threaded);
//@}
protected:
@@ -595,6 +619,7 @@ protected:
S32 mNextBaseChannel;
buffer_list_t mBuffers;
segment_list_t mSegments;
+ LLMutex* mMutexp;
};
#endif // LL_LLBUFFER_H
diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp
index 6257983c43..8d8ad05ad5 100644
--- a/indra/llmessage/llbufferstream.cpp
+++ b/indra/llmessage/llbufferstream.cpp
@@ -31,6 +31,7 @@
#include "llbuffer.h"
#include "llmemtype.h"
+#include "llthread.h"
static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4;
@@ -62,6 +63,7 @@ int LLBufferStreamBuf::underflow()
return EOF;
}
+ LLMutexLock lock(mBuffer->getMutex());
LLBufferArray::segment_iterator_t iter;
LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
U8* last_pos = (U8*)gptr();
@@ -149,6 +151,7 @@ int LLBufferStreamBuf::overflow(int c)
// since we got here, we have a buffer, and we have a character to
// put on it.
LLBufferArray::segment_iterator_t it;
+ LLMutexLock lock(mBuffer->getMutex());
it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE);
if(it != mBuffer->endSegment())
{
@@ -210,6 +213,7 @@ int LLBufferStreamBuf::sync()
// *NOTE: I bet we could just --address if address is not NULL.
// Need to think about that.
+ LLMutexLock lock(mBuffer->getMutex());
address = mBuffer->seek(mChannels.out(), address, -1);
if(address)
{
@@ -273,6 +277,8 @@ streampos LLBufferStreamBuf::seekoff(
// NULL is fine
break;
}
+
+ LLMutexLock lock(mBuffer->getMutex());
address = mBuffer->seek(mChannels.in(), base_addr, off);
if(address)
{
@@ -304,6 +310,8 @@ streampos LLBufferStreamBuf::seekoff(
// NULL is fine
break;
}
+
+ LLMutexLock lock(mBuffer->getMutex());
address = mBuffer->seek(mChannels.out(), base_addr, off);
if(address)
{
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 6d9213f51b..3bcaffc275 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -72,10 +72,9 @@
static const U32 EASY_HANDLE_POOL_SIZE = 5;
static const S32 MULTI_PERFORM_CALL_REPEAT = 5;
-static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds
+static const S32 CURL_REQUEST_TIMEOUT = 30; // seconds per operation
static const S32 MAX_ACTIVE_REQUEST_COUNT = 100;
-static
// DEBUG //
S32 gCurlEasyCount = 0;
S32 gCurlMultiCount = 0;
@@ -86,9 +85,12 @@ S32 gCurlMultiCount = 0;
std::vector<LLMutex*> LLCurl::sSSLMutex;
std::string LLCurl::sCAPath;
std::string LLCurl::sCAFile;
-
-bool LLCurl::sMultiThreaded = false;
-static U32 sMainThreadID = 0;
+LLCurlThread* LLCurl::sCurlThread = NULL ;
+LLMutex* LLCurl::sHandleMutexp = NULL ;
+S32 LLCurl::sTotalHandles = 0 ;
+bool LLCurl::sNotQuitting = true;
+F32 LLCurl::sCurlRequestTimeOut = 120.f; //seonds
+S32 LLCurl::sMaxHandles = 256; //max number of handles, (multi handles and easy handles combined).
void check_curl_code(CURLcode code)
{
@@ -221,17 +223,20 @@ namespace boost
std::set<CURL*> LLCurl::Easy::sFreeHandles;
std::set<CURL*> LLCurl::Easy::sActiveHandles;
-LLMutex* LLCurl::Easy::sHandleMutex = NULL;
-LLMutex* LLCurl::Easy::sMultiMutex = NULL;
+LLMutex* LLCurl::Easy::sHandleMutexp = NULL ;
//static
CURL* LLCurl::Easy::allocEasyHandle()
{
+ llassert(LLCurl::getCurlThread()) ;
+
CURL* ret = NULL;
- LLMutexLock lock(sHandleMutex);
+
+ LLMutexLock lock(sHandleMutexp) ;
+
if (sFreeHandles.empty())
{
- ret = curl_easy_init();
+ ret = LLCurl::newEasyHandle();
}
else
{
@@ -251,17 +256,27 @@ CURL* LLCurl::Easy::allocEasyHandle()
//static
void LLCurl::Easy::releaseEasyHandle(CURL* handle)
{
+ static const S32 MAX_NUM_FREE_HANDLES = 32 ;
+
if (!handle)
{
- llerrs << "handle cannot be NULL!" << llendl;
+ return ; //handle allocation failed.
+ //llerrs << "handle cannot be NULL!" << llendl;
}
- LLMutexLock lock(sHandleMutex);
-
+ LLMutexLock lock(sHandleMutexp) ;
if (sActiveHandles.find(handle) != sActiveHandles.end())
{
sActiveHandles.erase(handle);
- sFreeHandles.insert(handle);
+
+ if(sFreeHandles.size() < MAX_NUM_FREE_HANDLES)
+ {
+ sFreeHandles.insert(handle);
+ }
+ else
+ {
+ LLCurl::deleteEasyHandle(handle) ;
+ }
}
else
{
@@ -304,6 +319,14 @@ LLCurl::Easy::~Easy()
--gCurlEasyCount;
curl_slist_free_all(mHeaders);
for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
+
+ if (mResponder && LLCurl::sNotQuitting) //aborted
+ {
+ std::string reason("Request timeout, aborted.") ;
+ mResponder->completedRaw(408, //HTTP_REQUEST_TIME_OUT, timeout, abort
+ reason, mChannels, mOutput);
+ }
+ mResponder = NULL;
}
void LLCurl::Easy::resetState()
@@ -476,6 +499,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
LLProxy::getInstance()->applyProxySettings(this);
mOutput.reset(new LLBufferArray);
+ mOutput->setThreaded(true);
setopt(CURLOPT_WRITEFUNCTION, (void*)&curlWriteCallback);
setopt(CURLOPT_WRITEDATA, (void*)this);
@@ -519,48 +543,56 @@ void LLCurl::Easy::prepRequest(const std::string& url,
}
////////////////////////////////////////////////////////////////////////////
-
-LLCurl::Multi::Multi()
- : LLThread("Curl Multi"),
- mQueued(0),
+LLCurl::Multi::Multi(F32 idle_time_out)
+ : mQueued(0),
mErrorCount(0),
- mPerformState(PERFORM_STATE_READY)
+ mState(STATE_READY),
+ mDead(FALSE),
+ mMutexp(NULL),
+ mDeletionMutexp(NULL),
+ mEasyMutexp(NULL)
{
- mQuitting = false;
-
- mThreaded = LLCurl::sMultiThreaded && LLThread::currentID() == sMainThreadID;
- if (mThreaded)
- {
- mSignal = new LLCondition();
- }
- else
- {
- mSignal = NULL;
- }
-
- mCurlMultiHandle = curl_multi_init();
+ mCurlMultiHandle = LLCurl::newMultiHandle();
if (!mCurlMultiHandle)
{
llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
- mCurlMultiHandle = curl_multi_init();
+ mCurlMultiHandle = LLCurl::newMultiHandle();
}
- llassert_always(mCurlMultiHandle);
- ++gCurlMultiCount;
+ //llassert_always(mCurlMultiHandle);
+
+ if(mCurlMultiHandle)
+ {
+ if(LLCurl::getCurlThread()->getThreaded())
+ {
+ mMutexp = new LLMutex(NULL) ;
+ mDeletionMutexp = new LLMutex(NULL) ;
+ mEasyMutexp = new LLMutex(NULL) ;
+ }
+ LLCurl::getCurlThread()->addMulti(this) ;
+
+ mIdleTimeOut = idle_time_out ;
+ if(mIdleTimeOut < LLCurl::sCurlRequestTimeOut)
+ {
+ mIdleTimeOut = LLCurl::sCurlRequestTimeOut ;
+ }
+
+ ++gCurlMultiCount;
+ }
}
LLCurl::Multi::~Multi()
{
- llassert(isStopped());
+ cleanup() ;
+}
- if (LLCurl::sMultiThreaded)
+void LLCurl::Multi::cleanup()
+{
+ if(!mCurlMultiHandle)
{
- LLCurl::Easy::sMultiMutex->lock();
+ return ; //nothing to clean.
}
- delete mSignal;
- mSignal = NULL;
-
// Clean up active
for(easy_active_list_t::iterator iter = mEasyActiveList.begin();
iter != mEasyActiveList.end(); ++iter)
@@ -576,76 +608,157 @@ LLCurl::Multi::~Multi()
for_each(mEasyFreeList.begin(), mEasyFreeList.end(), DeletePointer());
mEasyFreeList.clear();
- check_curl_multi_code(curl_multi_cleanup(mCurlMultiHandle));
+ check_curl_multi_code(LLCurl::deleteMultiHandle(mCurlMultiHandle));
+ mCurlMultiHandle = NULL ;
+
+ delete mMutexp ;
+ mMutexp = NULL ;
+ delete mDeletionMutexp ;
+ mDeletionMutexp = NULL ;
+ delete mEasyMutexp ;
+ mEasyMutexp = NULL ;
+
+ mQueued = 0 ;
+ mState = STATE_COMPLETED;
+
--gCurlMultiCount;
- if (LLCurl::sMultiThreaded)
+ return ;
+}
+
+void LLCurl::Multi::lock()
+{
+ if(mMutexp)
{
- LLCurl::Easy::sMultiMutex->unlock();
+ mMutexp->lock() ;
}
}
-CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
+void LLCurl::Multi::unlock()
{
- CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue);
- return curlmsg;
+ if(mMutexp)
+ {
+ mMutexp->unlock() ;
+ }
+}
+
+void LLCurl::Multi::markDead()
+{
+ LLMutexLock lock(mDeletionMutexp) ;
+
+ mDead = TRUE ;
+ LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_URGENT) ;
}
-void LLCurl::Multi::perform()
+void LLCurl::Multi::setState(LLCurl::Multi::ePerformState state)
{
- if (mThreaded)
+ lock() ;
+ mState = state ;
+ unlock() ;
+
+ if(mState == STATE_READY)
{
- if (mPerformState == PERFORM_STATE_READY)
- {
- mSignal->signal();
- }
+ LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_NORMAL) ;
+ }
+}
+
+LLCurl::Multi::ePerformState LLCurl::Multi::getState()
+{
+ return mState;
+}
+
+bool LLCurl::Multi::isCompleted()
+{
+ return STATE_COMPLETED == getState() ;
+}
+
+bool LLCurl::Multi::waitToComplete()
+{
+ if(!isValid())
+ {
+ return true ;
}
- else
+
+ if(!mMutexp) //not threaded
+ {
+ doPerform() ;
+ return true ;
+ }
+
+ bool completed = (STATE_COMPLETED == mState) ;
+ if(!completed)
{
- doPerform();
+ LLCurl::getCurlThread()->setPriority(mHandle, LLQueuedThread::PRIORITY_HIGH) ;
}
+
+ return completed;
}
-void LLCurl::Multi::run()
+CURLMsg* LLCurl::Multi::info_read(S32* msgs_in_queue)
{
- llassert(mThreaded);
+ LLMutexLock lock(mMutexp) ;
- while (!mQuitting)
- {
- mSignal->wait();
- mPerformState = PERFORM_STATE_PERFORMING;
- if (!mQuitting)
- {
- LLMutexLock lock(LLCurl::Easy::sMultiMutex);
- doPerform();
- }
- }
+ CURLMsg* curlmsg = curl_multi_info_read(mCurlMultiHandle, msgs_in_queue);
+ return curlmsg;
}
-void LLCurl::Multi::doPerform()
+//return true if dead
+bool LLCurl::Multi::doPerform()
{
- S32 q = 0;
- for (S32 call_count = 0;
- call_count < MULTI_PERFORM_CALL_REPEAT;
- call_count += 1)
+ LLMutexLock lock(mDeletionMutexp) ;
+
+ bool dead = mDead ;
+
+ if(mDead)
{
- CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
- if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
+ setState(STATE_COMPLETED);
+ mQueued = 0 ;
+ }
+ else if(getState() != STATE_COMPLETED)
+ {
+ setState(STATE_PERFORMING);
+
+ S32 q = 0;
+ for (S32 call_count = 0;
+ call_count < MULTI_PERFORM_CALL_REPEAT;
+ call_count++)
{
- check_curl_multi_code(code);
- break;
+ LLMutexLock lock(mMutexp) ;
+
+ //WARNING: curl_multi_perform will block for many hundreds of milliseconds
+ // NEVER call this from the main thread, and NEVER allow the main thread to
+ // wait on a mutex held by this thread while curl_multi_perform is executing
+ CURLMcode code = curl_multi_perform(mCurlMultiHandle, &q);
+ if (CURLM_CALL_MULTI_PERFORM != code || q == 0)
+ {
+ check_curl_multi_code(code);
+
+ break;
+ }
}
-
+
+ mQueued = q;
+ setState(STATE_COMPLETED) ;
+ mIdleTimer.reset() ;
+ }
+ else if(mIdleTimer.getElapsedTimeF32() > mIdleTimeOut) //idle for too long, remove it.
+ {
+ dead = true ;
}
- mQueued = q;
- mPerformState = PERFORM_STATE_COMPLETED;
+
+ return dead ;
}
S32 LLCurl::Multi::process()
{
- perform();
+ if(!isValid())
+ {
+ return 0 ;
+ }
+
+ waitToComplete() ;
- if (mPerformState != PERFORM_STATE_COMPLETED)
+ if (getState() != STATE_COMPLETED)
{
return 0;
}
@@ -660,10 +773,19 @@ S32 LLCurl::Multi::process()
if (msg->msg == CURLMSG_DONE)
{
U32 response = 0;
- easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle);
- if (iter != mEasyActiveMap.end())
+ Easy* easy = NULL ;
+
+ {
+ LLMutexLock lock(mEasyMutexp) ;
+ easy_active_map_t::iterator iter = mEasyActiveMap.find(msg->easy_handle);
+ if (iter != mEasyActiveMap.end())
+ {
+ easy = iter->second;
+ }
+ }
+
+ if(easy)
{
- Easy* easy = iter->second;
response = easy->report(msg->data.result);
removeEasy(easy);
}
@@ -681,25 +803,28 @@ S32 LLCurl::Multi::process()
}
}
- mPerformState = PERFORM_STATE_READY;
+ setState(STATE_READY);
+
return processed;
}
LLCurl::Easy* LLCurl::Multi::allocEasy()
{
- Easy* easy = 0;
+ Easy* easy = 0;
if (mEasyFreeList.empty())
- {
+ {
easy = Easy::getEasy();
}
else
{
+ LLMutexLock lock(mEasyMutexp) ;
easy = *(mEasyFreeList.begin());
mEasyFreeList.erase(easy);
}
if (easy)
{
+ LLMutexLock lock(mEasyMutexp) ;
mEasyActiveList.insert(easy);
mEasyActiveMap[easy->getCurlHandle()] = easy;
}
@@ -708,6 +833,7 @@ LLCurl::Easy* LLCurl::Multi::allocEasy()
bool LLCurl::Multi::addEasy(Easy* easy)
{
+ LLMutexLock lock(mMutexp) ;
CURLMcode mcode = curl_multi_add_handle(mCurlMultiHandle, easy->getCurlHandle());
check_curl_multi_code(mcode);
//if (mcode != CURLM_OK)
@@ -720,25 +846,156 @@ bool LLCurl::Multi::addEasy(Easy* easy)
void LLCurl::Multi::easyFree(Easy* easy)
{
+ if(mEasyMutexp)
+ {
+ mEasyMutexp->lock() ;
+ }
+
mEasyActiveList.erase(easy);
mEasyActiveMap.erase(easy->getCurlHandle());
+
if (mEasyFreeList.size() < EASY_HANDLE_POOL_SIZE)
- {
- easy->resetState();
+ {
mEasyFreeList.insert(easy);
+
+ if(mEasyMutexp)
+ {
+ mEasyMutexp->unlock() ;
+ }
+
+ easy->resetState();
}
else
{
+ if(mEasyMutexp)
+ {
+ mEasyMutexp->unlock() ;
+ }
delete easy;
}
}
void LLCurl::Multi::removeEasy(Easy* easy)
{
- check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
+ {
+ LLMutexLock lock(mMutexp) ;
+ check_curl_multi_code(curl_multi_remove_handle(mCurlMultiHandle, easy->getCurlHandle()));
+ }
easyFree(easy);
}
+//------------------------------------------------------------
+//LLCurlThread
+LLCurlThread::CurlRequest::CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread) :
+ LLQueuedThread::QueuedRequest(handle, LLQueuedThread::PRIORITY_NORMAL, FLAG_AUTO_COMPLETE),
+ mMulti(multi),
+ mCurlThread(curl_thread)
+{
+}
+
+LLCurlThread::CurlRequest::~CurlRequest()
+{
+ if(mMulti)
+ {
+ mCurlThread->deleteMulti(mMulti) ;
+ mMulti = NULL ;
+ }
+}
+
+bool LLCurlThread::CurlRequest::processRequest()
+{
+ bool completed = true ;
+ if(mMulti)
+ {
+ completed = mCurlThread->doMultiPerform(mMulti) ;
+
+ if(!completed)
+ {
+ setPriority(LLQueuedThread::PRIORITY_LOW) ;
+ }
+ }
+
+ return completed ;
+}
+
+void LLCurlThread::CurlRequest::finishRequest(bool completed)
+{
+ if(mMulti->isDead())
+ {
+ mCurlThread->deleteMulti(mMulti) ;
+ }
+ else
+ {
+ mCurlThread->cleanupMulti(mMulti) ; //being idle too long, remove the request.
+ }
+
+ mMulti = NULL ;
+}
+
+LLCurlThread::LLCurlThread(bool threaded) :
+ LLQueuedThread("curlthread", threaded)
+{
+}
+
+//virtual
+LLCurlThread::~LLCurlThread()
+{
+}
+
+S32 LLCurlThread::update(F32 max_time_ms)
+{
+ return LLQueuedThread::update(max_time_ms);
+}
+
+void LLCurlThread::addMulti(LLCurl::Multi* multi)
+{
+ multi->mHandle = generateHandle() ;
+
+ CurlRequest* req = new CurlRequest(multi->mHandle, multi, this) ;
+
+ if (!addRequest(req))
+ {
+ llwarns << "curl request added when the thread is quitted" << llendl;
+ }
+}
+
+void LLCurlThread::killMulti(LLCurl::Multi* multi)
+{
+ if(!multi)
+ {
+ return ;
+ }
+
+ if(multi->isValid())
+ {
+ multi->markDead() ;
+ }
+ else
+ {
+ deleteMulti(multi) ;
+ }
+}
+
+//private
+bool LLCurlThread::doMultiPerform(LLCurl::Multi* multi)
+{
+ return multi->doPerform() ;
+}
+
+//private
+void LLCurlThread::deleteMulti(LLCurl::Multi* multi)
+{
+ delete multi ;
+}
+
+//private
+void LLCurlThread::cleanupMulti(LLCurl::Multi* multi)
+{
+ multi->cleanup() ;
+}
+
+//------------------------------------------------------------
+
//static
std::string LLCurl::strerror(CURLcode errorcode)
{
@@ -753,39 +1010,30 @@ LLCurlRequest::LLCurlRequest() :
mActiveMulti(NULL),
mActiveRequestCount(0)
{
- mThreadID = LLThread::currentID();
mProcessing = FALSE;
}
LLCurlRequest::~LLCurlRequest()
{
- llassert_always(mThreadID == LLThread::currentID());
-
//stop all Multi handle background threads
for (curlmulti_set_t::iterator iter = mMultiSet.begin(); iter != mMultiSet.end(); ++iter)
{
- LLCurl::Multi* multi = *iter;
- multi->mQuitting = true;
- if (multi->mThreaded)
- {
- while (!multi->isStopped())
- {
- multi->mSignal->signal();
- apr_sleep(1000);
- }
- }
+ LLCurl::getCurlThread()->killMulti(*iter) ;
}
- for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
+ mMultiSet.clear() ;
}
void LLCurlRequest::addMulti()
{
- llassert_always(mThreadID == LLThread::currentID());
LLCurl::Multi* multi = new LLCurl::Multi();
- if (multi->mThreaded)
+ if(!multi->isValid())
{
- multi->start();
+ LLCurl::getCurlThread()->killMulti(multi) ;
+ mActiveMulti = NULL ;
+ mActiveRequestCount = 0 ;
+ return;
}
+
mMultiSet.insert(multi);
mActiveMulti = multi;
mActiveRequestCount = 0;
@@ -799,7 +1047,12 @@ LLCurl::Easy* LLCurlRequest::allocEasy()
{
addMulti();
}
- llassert_always(mActiveMulti);
+ if(!mActiveMulti)
+ {
+ return NULL ;
+ }
+
+ //llassert_always(mActiveMulti);
++mActiveRequestCount;
LLCurl::Easy* easy = mActiveMulti->allocEasy();
return easy;
@@ -901,7 +1154,6 @@ bool LLCurlRequest::post(const std::string& url,
// Note: call once per frame
S32 LLCurlRequest::process()
{
- llassert_always(mThreadID == LLThread::currentID());
S32 res = 0;
mProcessing = TRUE;
@@ -910,22 +1162,25 @@ S32 LLCurlRequest::process()
{
curlmulti_set_t::iterator curiter = iter++;
LLCurl::Multi* multi = *curiter;
+
+ if(!multi->isValid())
+ {
+ if(multi == mActiveMulti)
+ {
+ mActiveMulti = NULL ;
+ mActiveRequestCount = 0 ;
+ }
+ mMultiSet.erase(curiter) ;
+ LLCurl::getCurlThread()->killMulti(multi) ;
+ continue ;
+ }
+
S32 tres = multi->process();
res += tres;
if (multi != mActiveMulti && tres == 0 && multi->mQueued == 0)
{
mMultiSet.erase(curiter);
- multi->mQuitting = true;
- if (multi->mThreaded)
- {
- while (!multi->isStopped())
- {
- multi->mSignal->signal();
- apr_sleep(1000);
- }
- }
-
- delete multi;
+ LLCurl::getCurlThread()->killMulti(multi);
}
}
mProcessing = FALSE;
@@ -934,15 +1189,27 @@ S32 LLCurlRequest::process()
S32 LLCurlRequest::getQueued()
{
- llassert_always(mThreadID == LLThread::currentID());
S32 queued = 0;
for (curlmulti_set_t::iterator iter = mMultiSet.begin();
iter != mMultiSet.end(); )
{
curlmulti_set_t::iterator curiter = iter++;
LLCurl::Multi* multi = *curiter;
+
+ if(!multi->isValid())
+ {
+ if(multi == mActiveMulti)
+ {
+ mActiveMulti = NULL ;
+ mActiveRequestCount = 0 ;
+ }
+ LLCurl::getCurlThread()->killMulti(multi);
+ mMultiSet.erase(curiter) ;
+ continue ;
+ }
+
queued += multi->mQueued;
- if (multi->mPerformState != LLCurl::Multi::PERFORM_STATE_READY)
+ if (multi->getState() != LLCurl::Multi::STATE_READY)
{
++queued;
}
@@ -959,37 +1226,34 @@ LLCurlEasyRequest::LLCurlEasyRequest()
mResultReturned(false)
{
mMulti = new LLCurl::Multi();
- if (mMulti->mThreaded)
+
+ if(mMulti->isValid())
{
- mMulti->start();
+ mEasy = mMulti->allocEasy();
+ if (mEasy)
+ {
+ mEasy->setErrorBuffer();
+ mEasy->setCA();
+ // Set proxy settings if configured to do so.
+ LLProxy::getInstance()->applyProxySettings(mEasy);
+ }
}
- mEasy = mMulti->allocEasy();
- if (mEasy)
+ else
{
- mEasy->setErrorBuffer();
- mEasy->setCA();
- // Set proxy settings if configured to do so.
- LLProxy::getInstance()->applyProxySettings(mEasy);
+ LLCurl::getCurlThread()->killMulti(mMulti) ;
+ mEasy = NULL ;
+ mMulti = NULL ;
}
}
LLCurlEasyRequest::~LLCurlEasyRequest()
{
- mMulti->mQuitting = true;
- if (mMulti->mThreaded)
- {
- while (!mMulti->isStopped())
- {
- mMulti->mSignal->signal();
- apr_sleep(1000);
- }
- }
- delete mMulti;
+ LLCurl::getCurlThread()->killMulti(mMulti) ;
}
void LLCurlEasyRequest::setopt(CURLoption option, S32 value)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setopt(option, value);
}
@@ -997,7 +1261,7 @@ void LLCurlEasyRequest::setopt(CURLoption option, S32 value)
void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setoptString(option, value);
}
@@ -1005,7 +1269,7 @@ void LLCurlEasyRequest::setoptString(CURLoption option, const std::string& value
void LLCurlEasyRequest::setPost(char* postdata, S32 size)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setopt(CURLOPT_POST, 1);
mEasy->setopt(CURLOPT_POSTFIELDS, postdata);
@@ -1015,7 +1279,7 @@ void LLCurlEasyRequest::setPost(char* postdata, S32 size)
void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* userdata)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setopt(CURLOPT_HEADERFUNCTION, (void*)callback);
mEasy->setopt(CURLOPT_HEADERDATA, userdata); // aka CURLOPT_WRITEHEADER
@@ -1024,7 +1288,7 @@ void LLCurlEasyRequest::setHeaderCallback(curl_header_callback callback, void* u
void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* userdata)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setopt(CURLOPT_WRITEFUNCTION, (void*)callback);
mEasy->setopt(CURLOPT_WRITEDATA, userdata);
@@ -1033,7 +1297,7 @@ void LLCurlEasyRequest::setWriteCallback(curl_write_callback callback, void* use
void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userdata)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setopt(CURLOPT_READFUNCTION, (void*)callback);
mEasy->setopt(CURLOPT_READDATA, userdata);
@@ -1042,7 +1306,7 @@ void LLCurlEasyRequest::setReadCallback(curl_read_callback callback, void* userd
void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void* userdata)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setopt(CURLOPT_SSL_CTX_FUNCTION, (void*)callback);
mEasy->setopt(CURLOPT_SSL_CTX_DATA, userdata);
@@ -1051,7 +1315,7 @@ void LLCurlEasyRequest::setSSLCtxCallback(curl_ssl_ctx_callback callback, void*
void LLCurlEasyRequest::slist_append(const char* str)
{
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->slist_append(str);
}
@@ -1062,7 +1326,7 @@ void LLCurlEasyRequest::sendRequest(const std::string& url)
llassert_always(!mRequestSent);
mRequestSent = true;
lldebugs << url << llendl;
- if (mEasy)
+ if (isValid() && mEasy)
{
mEasy->setHeaders();
mEasy->setoptString(CURLOPT_URL, url);
@@ -1074,25 +1338,24 @@ void LLCurlEasyRequest::requestComplete()
{
llassert_always(mRequestSent);
mRequestSent = false;
- if (mEasy)
+ if (isValid() && mEasy)
{
mMulti->removeEasy(mEasy);
}
}
-void LLCurlEasyRequest::perform()
-{
- mMulti->perform();
-}
-
// Usage: Call getRestult until it returns false (no more messages)
bool LLCurlEasyRequest::getResult(CURLcode* result, LLCurl::TransferInfo* info)
{
- if (mMulti->mPerformState != LLCurl::Multi::PERFORM_STATE_COMPLETED)
+ if(!isValid())
+ {
+ return false ;
+ }
+ if (!mMulti->isCompleted())
{ //we're busy, try again later
return false;
}
- mMulti->mPerformState = LLCurl::Multi::PERFORM_STATE_READY;
+ mMulti->setState(LLCurl::Multi::STATE_READY) ;
if (!mEasy)
{
@@ -1152,7 +1415,7 @@ CURLMsg* LLCurlEasyRequest::info_read(S32* q, LLCurl::TransferInfo* info)
std::string LLCurlEasyRequest::getErrorString()
{
- return mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();
+ return isValid() && mEasy ? std::string(mEasy->getErrorBuffer()) : std::string();
}
////////////////////////////////////////////////////////////////////////////
@@ -1178,10 +1441,11 @@ unsigned long LLCurl::ssl_thread_id(void)
}
#endif
-void LLCurl::initClass(bool multi_threaded)
+void LLCurl::initClass(F32 curl_reuest_timeout, S32 max_number_handles, bool multi_threaded)
{
- sMainThreadID = LLThread::currentID();
- sMultiThreaded = multi_threaded;
+ sCurlRequestTimeOut = curl_reuest_timeout ; //seconds
+ sMaxHandles = max_number_handles ; //max number of handles, (multi handles and easy handles combined).
+
// Do not change this "unless you are familiar with and mean to control
// internal operations of libcurl"
// - http://curl.haxx.se/libcurl/c/curl_global_init.html
@@ -1189,43 +1453,127 @@ void LLCurl::initClass(bool multi_threaded)
check_curl_code(code);
- Easy::sHandleMutex = new LLMutex();
- Easy::sMultiMutex = new LLMutex();
-
#if SAFE_SSL
S32 mutex_count = CRYPTO_num_locks();
for (S32 i=0; i<mutex_count; i++)
{
- sSSLMutex.push_back(new LLMutex);
+ sSSLMutex.push_back(new LLMutex(NULL));
}
CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
#endif
+
+ sCurlThread = new LLCurlThread(multi_threaded) ;
+ if(multi_threaded)
+ {
+ sHandleMutexp = new LLMutex(NULL) ;
+ Easy::sHandleMutexp = new LLMutex(NULL) ;
+ }
}
void LLCurl::cleanupClass()
{
+ sNotQuitting = false; //set quitting
+
+ //shut down curl thread
+ while(1)
+ {
+ if(!sCurlThread->update(1)) //finish all tasks
+ {
+ break ;
+ }
+ }
+ sCurlThread->shutdown() ;
+ delete sCurlThread ;
+ sCurlThread = NULL ;
+
#if SAFE_SSL
CRYPTO_set_locking_callback(NULL);
for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
#endif
- delete Easy::sHandleMutex;
- Easy::sHandleMutex = NULL;
- delete Easy::sMultiMutex;
- Easy::sMultiMutex = NULL;
-
for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
{
CURL* curl = *iter;
- curl_easy_cleanup(curl);
+ LLCurl::deleteEasyHandle(curl);
}
Easy::sFreeHandles.clear();
+ delete Easy::sHandleMutexp ;
+ Easy::sHandleMutexp = NULL ;
+
+ delete sHandleMutexp ;
+ sHandleMutexp = NULL ;
+
llassert(Easy::sActiveHandles.empty());
}
+//static
+CURLM* LLCurl::newMultiHandle()
+{
+ LLMutexLock lock(sHandleMutexp) ;
+
+ if(sTotalHandles + 1 > sMaxHandles)
+ {
+ llwarns << "no more handles available." << llendl ;
+ return NULL ; //failed
+ }
+ sTotalHandles++;
+
+ CURLM* ret = curl_multi_init() ;
+ if(!ret)
+ {
+ llwarns << "curl_multi_init failed." << llendl ;
+ }
+
+ return ret ;
+}
+
+//static
+CURLMcode LLCurl::deleteMultiHandle(CURLM* handle)
+{
+ if(handle)
+ {
+ LLMutexLock lock(sHandleMutexp) ;
+ sTotalHandles-- ;
+ return curl_multi_cleanup(handle) ;
+ }
+ return CURLM_OK ;
+}
+
+//static
+CURL* LLCurl::newEasyHandle()
+{
+ LLMutexLock lock(sHandleMutexp) ;
+
+ if(sTotalHandles + 1 > sMaxHandles)
+ {
+ llwarns << "no more handles available." << llendl ;
+ return NULL ; //failed
+ }
+ sTotalHandles++;
+
+ CURL* ret = curl_easy_init() ;
+ if(!ret)
+ {
+ llwarns << "curl_easy_init failed." << llendl ;
+ }
+
+ return ret ;
+}
+
+//static
+void LLCurl::deleteEasyHandle(CURL* handle)
+{
+ if(handle)
+ {
+ LLMutexLock lock(sHandleMutexp) ;
+ curl_easy_cleanup(handle) ;
+ sTotalHandles-- ;
+ }
+}
+
const unsigned int LLCurl::MAX_REDIRECTS = 5;
// Provide access to LLCurl free functions outside of llcurl.cpp without polluting the global namespace.
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 87de202717..fd664c0fa1 100755..100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -42,8 +42,11 @@
#include "lliopipe.h"
#include "llsd.h"
#include "llthread.h"
+#include "llqueuedthread.h"
+#include "llframetimer.h"
class LLMutex;
+class LLCurlThread;
// For whatever reason, this is not typedef'd in curl.h
typedef size_t (*curl_header_callback)(void *ptr, size_t size, size_t nmemb, void *stream);
@@ -56,8 +59,6 @@ public:
class Easy;
class Multi;
- static bool sMultiThreaded;
-
struct TransferInfo
{
TransferInfo() : mSizeDownload(0.0), mTotalTime(0.0), mSpeedDownload(0.0) {}
@@ -162,7 +163,7 @@ public:
/**
* @ brief Initialize LLCurl class
*/
- static void initClass(bool multi_threaded = false);
+ static void initClass(F32 curl_reuest_timeout = 120.f, S32 max_number_handles = 256, bool multi_threaded = false);
/**
* @ brief Cleanup LLCurl class
@@ -181,10 +182,25 @@ public:
static void ssl_locking_callback(int mode, int type, const char *file, int line);
static unsigned long ssl_thread_id(void);
+ static LLCurlThread* getCurlThread() { return sCurlThread ;}
+
+ static CURLM* newMultiHandle() ;
+ static CURLMcode deleteMultiHandle(CURLM* handle) ;
+ static CURL* newEasyHandle() ;
+ static void deleteEasyHandle(CURL* handle) ;
+
private:
static std::string sCAPath;
static std::string sCAFile;
static const unsigned int MAX_REDIRECTS;
+ static LLCurlThread* sCurlThread;
+
+ static LLMutex* sHandleMutexp ;
+ static S32 sTotalHandles ;
+ static S32 sMaxHandles;
+public:
+ static bool sNotQuitting;
+ static F32 sCurlRequestTimeOut;
};
class LLCurl::Easy
@@ -216,7 +232,7 @@ public:
U32 report(CURLcode);
void getTransferInfo(LLCurl::TransferInfo* info);
- void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, S32 time_out = 0, bool post = false);
+ void prepRequest(const std::string& url, const std::vector<std::string>& headers, LLCurl::ResponderPtr, S32 time_out = 0, bool post = false);
const char* getErrorBuffer();
@@ -247,64 +263,120 @@ private:
// Note: char*'s not strings since we pass pointers to curl
std::vector<char*> mStrings;
- ResponderPtr mResponder;
+ LLCurl::ResponderPtr mResponder;
static std::set<CURL*> sFreeHandles;
static std::set<CURL*> sActiveHandles;
- static LLMutex* sHandleMutex;
- static LLMutex* sMultiMutex;
+ static LLMutex* sHandleMutexp ;
};
-class LLCurl::Multi : public LLThread
+class LLCurl::Multi
{
LOG_CLASS(Multi);
+
+ friend class LLCurlThread ;
+
+private:
+ ~Multi();
+
+ void markDead() ;
+ bool doPerform();
+
public:
typedef enum
{
- PERFORM_STATE_READY=0,
- PERFORM_STATE_PERFORMING=1,
- PERFORM_STATE_COMPLETED=2
+ STATE_READY=0,
+ STATE_PERFORMING=1,
+ STATE_COMPLETED=2
} ePerformState;
- Multi();
- ~Multi();
+ Multi(F32 idle_time_out = 0.f);
- Easy* allocEasy();
- bool addEasy(Easy* easy);
+ LLCurl::Easy* allocEasy();
+ bool addEasy(LLCurl::Easy* easy);
+ void removeEasy(LLCurl::Easy* easy);
- void removeEasy(Easy* easy);
+ void lock() ;
+ void unlock() ;
- S32 process();
- void perform();
- void doPerform();
+ void setState(ePerformState state) ;
+ ePerformState getState() ;
- virtual void run();
+ bool isCompleted() ;
+ bool isValid() {return mCurlMultiHandle != NULL ;}
+ bool isDead() {return mDead;}
+
+ bool waitToComplete() ;
+ S32 process();
+
CURLMsg* info_read(S32* msgs_in_queue);
S32 mQueued;
S32 mErrorCount;
- S32 mPerformState;
-
- LLCondition* mSignal;
- bool mQuitting;
- bool mThreaded;
-
private:
- void easyFree(Easy*);
+ void easyFree(LLCurl::Easy*);
+ void cleanup() ;
CURLM* mCurlMultiHandle;
- typedef std::set<Easy*> easy_active_list_t;
+ typedef std::set<LLCurl::Easy*> easy_active_list_t;
easy_active_list_t mEasyActiveList;
- typedef std::map<CURL*, Easy*> easy_active_map_t;
+ typedef std::map<CURL*, LLCurl::Easy*> easy_active_map_t;
easy_active_map_t mEasyActiveMap;
- typedef std::set<Easy*> easy_free_list_t;
+ typedef std::set<LLCurl::Easy*> easy_free_list_t;
easy_free_list_t mEasyFreeList;
+
+ LLQueuedThread::handle_t mHandle ;
+ ePerformState mState;
+
+ BOOL mDead ;
+ LLMutex* mMutexp ;
+ LLMutex* mDeletionMutexp ;
+ LLMutex* mEasyMutexp ;
+ LLFrameTimer mIdleTimer ;
+ F32 mIdleTimeOut;
};
+class LLCurlThread : public LLQueuedThread
+{
+public:
+
+ class CurlRequest : public LLQueuedThread::QueuedRequest
+ {
+ protected:
+ virtual ~CurlRequest(); // use deleteRequest()
+
+ public:
+ CurlRequest(handle_t handle, LLCurl::Multi* multi, LLCurlThread* curl_thread);
+
+ /*virtual*/ bool processRequest();
+ /*virtual*/ void finishRequest(bool completed);
+
+ private:
+ // input
+ LLCurl::Multi* mMulti;
+ LLCurlThread* mCurlThread;
+ };
+ friend class CurlRequest;
+
+public:
+ LLCurlThread(bool threaded = true) ;
+ virtual ~LLCurlThread() ;
+
+ S32 update(F32 max_time_ms);
+
+ void addMulti(LLCurl::Multi* multi) ;
+ void killMulti(LLCurl::Multi* multi) ;
+
+private:
+ bool doMultiPerform(LLCurl::Multi* multi) ;
+ void deleteMulti(LLCurl::Multi* multi) ;
+ void cleanupMulti(LLCurl::Multi* multi) ;
+} ;
+
namespace boost
{
void intrusive_ptr_add_ref(LLCurl::Responder* p);
@@ -339,7 +411,6 @@ private:
LLCurl::Multi* mActiveMulti;
S32 mActiveRequestCount;
BOOL mProcessing;
- U32 mThreadID; // debug
};
class LLCurlEasyRequest
@@ -357,9 +428,11 @@ public:
void slist_append(const char* str);
void sendRequest(const std::string& url);
void requestComplete();
- void perform();
bool getResult(CURLcode* result, LLCurl::TransferInfo* info = NULL);
std::string getErrorString();
+ bool isCompleted() {return mMulti->isCompleted() ;}
+ bool wait() { return mMulti->waitToComplete(); }
+ bool isValid() {return mMulti && mMulti->isValid(); }
LLCurl::Easy* getEasy() const { return mEasy; }
diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp
index 2bca517e97..612d765969 100644
--- a/indra/llmessage/llhttpassetstorage.cpp
+++ b/indra/llmessage/llhttpassetstorage.cpp
@@ -232,7 +232,8 @@ LLSD LLHTTPAssetRequest::getFullDetails() const
void LLHTTPAssetRequest::setupCurlHandle()
{
// *NOTE: Similar code exists in mapserver/llcurlutil.cpp JC
- mCurlHandle = curl_easy_init();
+ mCurlHandle = LLCurl::newEasyHandle();
+ llassert_always(mCurlHandle != NULL) ;
// Apply proxy settings if configured to do so
LLProxy::getInstance()->applyProxySettings(mCurlHandle);
@@ -278,7 +279,7 @@ void LLHTTPAssetRequest::setupCurlHandle()
void LLHTTPAssetRequest::cleanupCurlHandle()
{
- curl_easy_cleanup(mCurlHandle);
+ LLCurl::deleteEasyHandle(mCurlHandle);
if (mAssetStoragep)
{
// Terminating a request. Thus upload or download is no longer pending.
@@ -429,12 +430,13 @@ void LLHTTPAssetStorage::_init(const std::string& web_host, const std::string& l
// curl_global_init moved to LLCurl::initClass()
- mCurlMultiHandle = curl_multi_init();
+ mCurlMultiHandle = LLCurl::newMultiHandle() ;
+ llassert_always(mCurlMultiHandle != NULL) ;
}
LLHTTPAssetStorage::~LLHTTPAssetStorage()
{
- curl_multi_cleanup(mCurlMultiHandle);
+ LLCurl::deleteMultiHandle(mCurlMultiHandle);
mCurlMultiHandle = NULL;
// curl_global_cleanup moved to LLCurl::initClass()
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index dd4e3a6300..231cb7ca8f 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -228,6 +228,12 @@ static void request(
LLPumpIO::chain_t chain;
LLURLRequest* req = new LLURLRequest(method, url);
+ if(!req->isValid())//failed
+ {
+ delete req ;
+ return ;
+ }
+
req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
@@ -423,7 +429,9 @@ static LLSD blocking_request(
{
lldebugs << "blockingRequest of " << url << llendl;
char curl_error_buffer[CURL_ERROR_SIZE] = "\0";
- CURL* curlp = curl_easy_init();
+ CURL* curlp = LLCurl::newEasyHandle();
+ llassert_always(curlp != NULL) ;
+
LLHTTPBuffer http_buffer;
std::string body_str;
@@ -517,7 +525,7 @@ static LLSD blocking_request(
}
// * Cleanup
- curl_easy_cleanup(curlp);
+ LLCurl::deleteEasyHandle(curlp);
return response;
}
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index 920a57ab55..987f386aa3 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -818,6 +818,8 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
// Copy everything after mLast read to the out.
LLBufferArray::segment_iterator_t seg_iter;
+
+ buffer->lock();
seg_iter = buffer->splitAfter(mLastRead);
if(seg_iter != buffer->endSegment())
{
@@ -838,7 +840,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
}
#endif
}
-
+ buffer->unlock();
//
// *FIX: get rid of extra bytes off the end
//
@@ -963,9 +965,13 @@ private:
// static
-LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port)
+LLHTTPNode& LLIOHTTPServer::create(
+ apr_pool_t* pool, LLPumpIO& pump, U16 port)
{
- LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP, port);
+ LLSocket::ptr_t socket = LLSocket::create(
+ pool,
+ LLSocket::STREAM_TCP,
+ port);
if(!socket)
{
llerrs << "Unable to initialize socket" << llendl;
@@ -974,7 +980,7 @@ LLHTTPNode& LLIOHTTPServer::create(LLPumpIO& pump, U16 port)
LLHTTPResponseFactory* factory = new LLHTTPResponseFactory;
boost::shared_ptr<LLChainIOFactory> factory_ptr(factory);
- LLIOServerSocket* server = new LLIOServerSocket(socket, factory_ptr);
+ LLIOServerSocket* server = new LLIOServerSocket(pool, socket, factory_ptr);
LLPumpIO::chain_t chain;
chain.push_back(LLIOPipe::ptr_t(server));
diff --git a/indra/llmessage/lliohttpserver.h b/indra/llmessage/lliohttpserver.h
index 2294e4b8ae..5c1b0531ff 100644
--- a/indra/llmessage/lliohttpserver.h
+++ b/indra/llmessage/lliohttpserver.h
@@ -50,7 +50,7 @@ class LLIOHTTPServer
public:
typedef void (*timing_callback_t)(const char* hashed_name, F32 time, void* data);
- static LLHTTPNode& create(LLPumpIO& pump, U16 port);
+ static LLHTTPNode& create(apr_pool_t* pool, LLPumpIO& pump, U16 port);
/**< Creates an HTTP wire server on the pump for the given TCP port.
*
* Returns the root node of the new server. Add LLHTTPNode instances
diff --git a/indra/llmessage/lliopipe.cpp b/indra/llmessage/lliopipe.cpp
index 6e4eec74a6..8f827f7a30 100644
--- a/indra/llmessage/lliopipe.cpp
+++ b/indra/llmessage/lliopipe.cpp
@@ -75,6 +75,12 @@ LLIOPipe::~LLIOPipe()
//lldebugs << "destroying LLIOPipe" << llendl;
}
+//virtual
+bool LLIOPipe::isValid()
+{
+ return true ;
+}
+
// static
std::string LLIOPipe::lookupStatusString(EStatus status)
{
diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h
index 8e656b6da1..cbd17b5a3d 100644
--- a/indra/llmessage/lliopipe.h
+++ b/indra/llmessage/lliopipe.h
@@ -231,6 +231,8 @@ public:
*/
virtual ~LLIOPipe();
+ virtual bool isValid() ;
+
protected:
/**
* @brief Base Constructor.
diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp
index a885ba8ee1..d5b4d45821 100644
--- a/indra/llmessage/lliosocket.cpp
+++ b/indra/llmessage/lliosocket.cpp
@@ -35,7 +35,6 @@
#include "llhost.h"
#include "llmemtype.h"
#include "llpumpio.h"
-#include "llthread.h"
//
// constants
@@ -99,31 +98,51 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
///
// static
-LLSocket::ptr_t LLSocket::create(EType type, U16 port)
+LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
+ LLSocket::ptr_t rv;
+ apr_socket_t* socket = NULL;
+ apr_pool_t* new_pool = NULL;
apr_status_t status = APR_EGENERAL;
- LLSocket::ptr_t rv(new LLSocket);
+
+ // create a pool for the socket
+ status = apr_pool_create(&new_pool, pool);
+ if(ll_apr_warn_status(status))
+ {
+ if(new_pool) apr_pool_destroy(new_pool);
+ return rv;
+ }
if(STREAM_TCP == type)
{
- status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());
+ status = apr_socket_create(
+ &socket,
+ APR_INET,
+ SOCK_STREAM,
+ APR_PROTO_TCP,
+ new_pool);
}
else if(DATAGRAM_UDP == type)
{
- status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());
+ status = apr_socket_create(
+ &socket,
+ APR_INET,
+ SOCK_DGRAM,
+ APR_PROTO_UDP,
+ new_pool);
}
else
{
- rv.reset();
+ if(new_pool) apr_pool_destroy(new_pool);
return rv;
}
if(ll_apr_warn_status(status))
{
- rv->mSocket = NULL;
- rv.reset();
+ if(new_pool) apr_pool_destroy(new_pool);
return rv;
}
+ rv = ptr_t(new LLSocket(socket, new_pool));
if(port > 0)
{
apr_sockaddr_t* sa = NULL;
@@ -133,7 +152,7 @@ LLSocket::ptr_t LLSocket::create(EType type, U16 port)
APR_UNSPEC,
port,
0,
- rv->mPool());
+ new_pool);
if(ll_apr_warn_status(status))
{
rv.reset();
@@ -141,8 +160,8 @@ LLSocket::ptr_t LLSocket::create(EType type, U16 port)
}
// This allows us to reuse the address on quick down/up. This
// is unlikely to create problems.
- ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1));
- status = apr_socket_bind(rv->mSocket, sa);
+ ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
+ status = apr_socket_bind(socket, sa);
if(ll_apr_warn_status(status))
{
rv.reset();
@@ -156,7 +175,7 @@ LLSocket::ptr_t LLSocket::create(EType type, U16 port)
// to keep a queue of incoming connections for ACCEPT.
lldebugs << "Setting listen state for socket." << llendl;
status = apr_socket_listen(
- rv->mSocket,
+ socket,
LL_DEFAULT_LISTEN_BACKLOG);
if(ll_apr_warn_status(status))
{
@@ -177,28 +196,21 @@ LLSocket::ptr_t LLSocket::create(EType type, U16 port)
}
// static
-LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket)
+LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
- if (!listen_socket->getSocket())
+ LLSocket::ptr_t rv;
+ if(!socket)
{
- status = APR_ENOSOCKET;
- return LLSocket::ptr_t();
- }
- LLSocket::ptr_t rv(new LLSocket);
- lldebugs << "accepting socket" << llendl;
- status = apr_socket_accept(&rv->mSocket, listen_socket->getSocket(), rv->mPool());
- if (status != APR_SUCCESS)
- {
- rv->mSocket = NULL;
- rv.reset();
return rv;
}
+ rv = ptr_t(new LLSocket(socket, pool));
rv->mPort = PORT_EPHEMERAL;
rv->setNonBlocking();
return rv;
}
+
bool LLSocket::blockingConnect(const LLHost& host)
{
if(!mSocket) return false;
@@ -211,7 +223,7 @@ bool LLSocket::blockingConnect(const LLHost& host)
APR_UNSPEC,
host.getPort(),
0,
- mPool())))
+ mPool)))
{
return false;
}
@@ -222,11 +234,13 @@ bool LLSocket::blockingConnect(const LLHost& host)
return true;
}
-LLSocket::LLSocket() :
- mSocket(NULL),
- mPool(LLThread::tldata().mRootPool),
+LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) :
+ mSocket(socket),
+ mPool(pool),
mPort(PORT_INVALID)
{
+ ll_debug_socket("Constructing wholely formed socket", mSocket);
+ LLMemType m1(LLMemType::MTYPE_IO_TCP);
}
LLSocket::~LLSocket()
@@ -239,6 +253,10 @@ LLSocket::~LLSocket()
apr_socket_close(mSocket);
mSocket = NULL;
}
+ if(mPool)
+ {
+ apr_pool_destroy(mPool);
+ }
}
// See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4
@@ -427,6 +445,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
// efficient - not only because writev() is better, but also
// because we won't have to do as much work to find the start
// address.
+ buffer->lock();
LLBufferArray::segment_iterator_t it;
LLBufferArray::segment_iterator_t end = buffer->endSegment();
LLSegment segment;
@@ -506,6 +525,8 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
}
}
+ buffer->unlock();
+
PUMP_DEBUG;
if(done && eos)
{
@@ -520,8 +541,10 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl(
///
LLIOServerSocket::LLIOServerSocket(
+ apr_pool_t* pool,
LLIOServerSocket::socket_t listener,
factory_t factory) :
+ mPool(pool),
mListenSocket(listener),
mReactor(factory),
mInitialized(false),
@@ -583,15 +606,21 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
lldebugs << "accepting socket" << llendl;
PUMP_DEBUG;
- apr_status_t status;
- LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket));
+ apr_pool_t* new_pool = NULL;
+ apr_status_t status = apr_pool_create(&new_pool, mPool);
+ apr_socket_t* socket = NULL;
+ status = apr_socket_accept(
+ &socket,
+ mListenSocket->getSocket(),
+ new_pool);
+ LLSocket::ptr_t llsocket(LLSocket::create(socket, new_pool));
//EStatus rv = STATUS_ERROR;
- if(llsocket && status == APR_SUCCESS)
+ if(llsocket)
{
PUMP_DEBUG;
apr_sockaddr_t* remote_addr;
- apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket());
+ apr_socket_addr_get(&remote_addr, APR_REMOTE, socket);
char* remote_host_string;
apr_sockaddr_ip_get(&remote_host_string, remote_addr);
@@ -606,6 +635,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
{
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
pump->addChain(chain, mResponseTimeout);
+ status = STATUS_OK;
}
else
{
@@ -614,8 +644,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
}
else
{
- char buf[256];
- llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
+ llwarns << "Unable to create linden socket." << llendl;
}
PUMP_DEBUG;
@@ -628,10 +657,11 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
#if 0
LLIODataSocket::LLIODataSocket(
U16 suggested_port,
- U16 start_discovery_port) :
+ U16 start_discovery_port,
+ apr_pool_t* pool) :
mSocket(NULL)
{
- if(PORT_INVALID == suggested_port) return;
+ if(!pool || (PORT_INVALID == suggested_port)) return;
if(ll_apr_warn_status(apr_socket_create(&mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, pool))) return;
apr_sockaddr_t* sa = NULL;
if(ll_apr_warn_status(apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, suggested_port, 0, pool))) return;
diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h
index f0a6f25657..be0f7dfcc6 100644
--- a/indra/llmessage/lliosocket.h
+++ b/indra/llmessage/lliosocket.h
@@ -38,6 +38,7 @@
*/
#include "lliopipe.h"
+#include "apr_pools.h"
#include "apr_network_io.h"
#include "llchainio.h"
@@ -87,22 +88,34 @@ public:
* socket. If you intend the socket to be known to external
* clients without prior port notification, do not use
* PORT_EPHEMERAL.
+ * @param pool The apr pool to use. A child pool will be created
+ * and associated with the socket.
* @param type The type of socket to create
* @param port The port for the socket
* @return A valid socket shared pointer if the call worked.
*/
static ptr_t create(
+ apr_pool_t* pool,
EType type,
U16 port = PORT_EPHEMERAL);
/**
- * @brief Create a LLSocket by accepting a connection from a listen socket.
+ * @brief Create a LLSocket when you already have an apr socket.
*
- * @param status Output. Status of the accept if a valid listen socket was passed.
- * @param listen_socket The listen socket to use.
+ * This method assumes an ephemeral port. This is typically used
+ * by calls which spawn a socket such as a call to
+ * <code>accept()</code> as in the server socket. This call should
+ * not fail if you have a valid apr socket.
+ * Because of the nature of how accept() works, you are expected
+ * to create a new pool for the socket, use that pool for the
+ * accept, and pass it in here where it will be bound with the
+ * socket and destroyed at the same time.
+ * @param socket The apr socket to use
+ * @param pool The pool used to create the socket. *NOTE: The pool
+ * passed in will be DESTROYED.
* @return A valid socket shared pointer if the call worked.
*/
- static ptr_t create(apr_status_t& status, ptr_t& listen_socket);
+ static ptr_t create(apr_socket_t* socket, apr_pool_t* pool);
/**
* @brief Perform a blocking connect to a host. Do not use in production.
@@ -133,12 +146,6 @@ public:
apr_socket_t* getSocket() const { return mSocket; }
/**
- * @brief Protected constructor since should only make sockets
- * with one of the two <code>create()</code> calls.
- */
- LLSocket(void);
-
- /**
* @brief Set default socket options, with SO_NONBLOCK = 0 and a timeout in us.
* @param timeout Number of microseconds to wait on this socket. Any
* negative number means block-forever. TIMEOUT OF 0 IS NON-PORTABLE.
@@ -167,8 +174,8 @@ protected:
// The apr socket.
apr_socket_t* mSocket;
- // Our memory pool.
- LLAPRPool mPool;
+ // our memory pool
+ apr_pool_t* mPool;
// The port if we know it.
U16 mPort;
@@ -293,7 +300,7 @@ class LLIOServerSocket : public LLIOPipe
public:
typedef LLSocket::ptr_t socket_t;
typedef boost::shared_ptr<LLChainIOFactory> factory_t;
- LLIOServerSocket(socket_t listener, factory_t reactor);
+ LLIOServerSocket(apr_pool_t* pool, socket_t listener, factory_t reactor);
virtual ~LLIOServerSocket();
/**
@@ -325,6 +332,7 @@ protected:
//@}
protected:
+ apr_pool_t* mPool;
socket_t mListenSocket;
factory_t mReactor;
bool mInitialized;
@@ -358,7 +366,8 @@ public:
*/
LLIODataSocket(
U16 suggested_port,
- U16 start_discovery_port);
+ U16 start_discovery_port,
+ apr_pool_t* pool);
virtual ~LLIODataSocket();
protected:
diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp
index 8a898ab1b0..08b31e9c7a 100644
--- a/indra/llmessage/llmail.cpp
+++ b/indra/llmessage/llmail.cpp
@@ -50,7 +50,6 @@
#include "llstring.h"
#include "lluuid.h"
#include "net.h"
-#include "llaprpool.h"
//
// constants
@@ -58,7 +57,7 @@
const size_t LL_MAX_KNOWN_GOOD_MAIL_SIZE = 4096;
static bool gMailEnabled = true;
-static LLAPRPool gMailPool;
+static apr_pool_t* gMailPool;
static apr_sockaddr_t* gSockAddr;
static apr_socket_t* gMailSocket;
@@ -83,7 +82,7 @@ bool connect_smtp()
gSockAddr->sa.sin.sin_family,
SOCK_STREAM,
APR_PROTO_TCP,
- gMailPool());
+ gMailPool);
if(ll_apr_warn_status(status)) return false;
status = apr_socket_connect(gMailSocket, gSockAddr);
if(ll_apr_warn_status(status))
@@ -140,19 +139,19 @@ BOOL LLMail::send(
}
// static
-void LLMail::init(const std::string& hostname)
+void LLMail::init(const std::string& hostname, apr_pool_t* pool)
{
gMailSocket = NULL;
- if (hostname.empty())
+ if(hostname.empty() || !pool)
{
+ gMailPool = NULL;
gSockAddr = NULL;
- gMailPool.destroy();
}
else
{
- gMailPool.create();
+ gMailPool = pool;
- // Collect all the information into a sockaddr structure. the
+ // collect all the information into a socaddr sturcture. the
// documentation is a bit unclear, but I either have to
// specify APR_UNSPEC or not specify any flags. I am not sure
// which option is better.
@@ -162,7 +161,7 @@ void LLMail::init(const std::string& hostname)
APR_UNSPEC,
25,
APR_IPV4_ADDR_OK,
- gMailPool());
+ gMailPool);
ll_apr_warn_status(status);
}
}
diff --git a/indra/llmessage/llmail.h b/indra/llmessage/llmail.h
index 0a5c532088..3791714363 100644
--- a/indra/llmessage/llmail.h
+++ b/indra/llmessage/llmail.h
@@ -27,13 +27,15 @@
#ifndef LL_LLMAIL_H
#define LL_LLMAIL_H
+typedef struct apr_pool_t apr_pool_t;
+
#include "llsd.h"
class LLMail
{
public:
// if hostname is NULL, then the host is resolved as 'mail'
- static void init(const std::string& hostname);
+ static void init(const std::string& hostname, apr_pool_t* pool);
// Allow all email transmission to be disabled/enabled.
static void enable(bool mail_enabled);
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index 4a7d326c0e..9988fcd9c0 100644
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -49,7 +49,7 @@ static void tcp_close_channel(LLSocket::ptr_t* handle_ptr); // Close an open TCP
LLProxy::LLProxy():
mHTTPProxyEnabled(false),
- mProxyMutex(),
+ mProxyMutex(NULL),
mUDPProxy(),
mTCPProxy(),
mHTTPProxy(),
@@ -524,7 +524,7 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
*/
static LLSocket::ptr_t tcp_open_channel(LLHost host)
{
- LLSocket::ptr_t socket = LLSocket::create(LLSocket::STREAM_TCP);
+ LLSocket::ptr_t socket = LLSocket::create(NULL, LLSocket::STREAM_TCP);
bool connected = socket->blockingConnect(host);
if (!connected)
{
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index 89cfd66e1b..f3ef4f2684 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -37,7 +37,6 @@
#include "llmemtype.h"
#include "llstl.h"
#include "llstat.h"
-#include "llthread.h"
// These should not be enabled in production, but they can be
// intensely useful during development for finding certain kinds of
@@ -163,12 +162,14 @@ struct ll_delete_apr_pollset_fd_client_data
/**
* LLPumpIO
*/
-LLPumpIO::LLPumpIO(void) :
+LLPumpIO::LLPumpIO(apr_pool_t* pool) :
mState(LLPumpIO::NORMAL),
mRebuildPollset(false),
mPollset(NULL),
mPollsetClientID(0),
mNextLock(0),
+ mPool(NULL),
+ mCurrentPool(NULL),
mCurrentPoolReallocCount(0),
mChainsMutex(NULL),
mCallbackMutex(NULL),
@@ -177,27 +178,24 @@ LLPumpIO::LLPumpIO(void) :
mCurrentChain = mRunningChains.end();
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
- initialize();
+ initialize(pool);
}
LLPumpIO::~LLPumpIO()
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-#if LL_THREADS_APR
- if (mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
- if (mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
-#endif
- mChainsMutex = NULL;
- mCallbackMutex = NULL;
- if(mPollset)
- {
-// lldebugs << "cleaning up pollset" << llendl;
- apr_pollset_destroy(mPollset);
- mPollset = NULL;
- }
+ cleanup();
+}
+
+bool LLPumpIO::prime(apr_pool_t* pool)
+{
+ LLMemType m1(LLMemType::MTYPE_IO_PUMP);
+ cleanup();
+ initialize(pool);
+ return ((pool == NULL) ? false : true);
}
-bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
+bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request)
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
if(chain.empty()) return false;
@@ -206,8 +204,10 @@ bool LLPumpIO::addChain(const chain_t& chain, F32 timeout)
LLScopedLock lock(mChainsMutex);
#endif
LLChainInfo info;
+ info.mHasCurlRequest = has_curl_request;
info.setTimeoutSeconds(timeout);
info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray);
+ info.mData->setThreaded(has_curl_request);
LLLinkInfo link;
#if LL_DEBUG_PIPE_TYPE_IN_PUMP
lldebugs << "LLPumpIO::addChain() " << chain[0] << " '"
@@ -354,7 +354,8 @@ bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll)
{
// each fd needs a pool to work with, so if one was
// not specified, use this pool.
- value.second.p = (*mCurrentChain).mDescriptorsPool->operator()();
+ // *FIX: Should it always be this pool?
+ value.second.p = mPool;
}
value.second.client_data = new S32(++mPollsetClientID);
(*mCurrentChain).mDescriptors.push_back(value);
@@ -441,6 +442,15 @@ void LLPumpIO::pump()
static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
+LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain)
+{
+ std::for_each(
+ (*run_chain).mDescriptors.begin(),
+ (*run_chain).mDescriptors.end(),
+ ll_delete_apr_pollset_fd_client_data());
+ return mRunningChains.erase(run_chain);
+}
+
//timeout is in microseconds
void LLPumpIO::pump(const S32& poll_timeout)
{
@@ -586,10 +596,16 @@ void LLPumpIO::pump(const S32& poll_timeout)
// << (*run_chain).mChainLinks[0].mPipe
// << " because we reached the end." << llendl;
#endif
- run_chain = mRunningChains.erase(run_chain);
+ run_chain = removeRunningChain(run_chain);
continue;
}
}
+ else if(isChainExpired(*run_chain))
+ {
+ run_chain = removeRunningChain(run_chain);
+ continue;
+ }
+
PUMP_DEBUG;
if((*run_chain).mLock)
{
@@ -697,11 +713,7 @@ void LLPumpIO::pump(const S32& poll_timeout)
PUMP_DEBUG;
// This chain is done. Clean up any allocated memory and
// erase the chain info.
- std::for_each(
- (*run_chain).mDescriptors.begin(),
- (*run_chain).mDescriptors.end(),
- ll_delete_apr_pollset_fd_client_data());
- run_chain = mRunningChains.erase(run_chain);
+ run_chain = removeRunningChain(run_chain);
// *NOTE: may not always need to rebuild the pollset.
mRebuildPollset = true;
@@ -826,15 +838,39 @@ void LLPumpIO::control(LLPumpIO::EControl op)
}
}
-void LLPumpIO::initialize(void)
+void LLPumpIO::initialize(apr_pool_t* pool)
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
- mPool.create();
+ if(!pool) return;
#if LL_THREADS_APR
// SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly.
- apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
- apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, mPool());
+ apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool);
+ apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool);
#endif
+ mPool = pool;
+}
+
+void LLPumpIO::cleanup()
+{
+ LLMemType m1(LLMemType::MTYPE_IO_PUMP);
+#if LL_THREADS_APR
+ if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
+ if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
+#endif
+ mChainsMutex = NULL;
+ mCallbackMutex = NULL;
+ if(mPollset)
+ {
+// lldebugs << "cleaning up pollset" << llendl;
+ apr_pollset_destroy(mPollset);
+ mPollset = NULL;
+ }
+ if(mCurrentPool)
+ {
+ apr_pool_destroy(mCurrentPool);
+ mCurrentPool = NULL;
+ }
+ mPool = NULL;
}
void LLPumpIO::rebuildPollset()
@@ -862,19 +898,21 @@ void LLPumpIO::rebuildPollset()
if(mCurrentPool
&& (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT)))
{
- mCurrentPool.destroy();
+ apr_pool_destroy(mCurrentPool);
+ mCurrentPool = NULL;
mCurrentPoolReallocCount = 0;
}
if(!mCurrentPool)
{
- mCurrentPool.create(mPool);
+ apr_status_t status = apr_pool_create(&mCurrentPool, mPool);
+ (void)ll_apr_warn_status(status);
}
// add all of the file descriptors
run_it = mRunningChains.begin();
LLChainInfo::conditionals_t::iterator fd_it;
LLChainInfo::conditionals_t::iterator fd_end;
- apr_pollset_create(&mPollset, size, mCurrentPool(), 0);
+ apr_pollset_create(&mPollset, size, mCurrentPool, 0);
for(; run_it != run_end; ++run_it)
{
fd_it = (*run_it).mDescriptors.begin();
@@ -1070,6 +1108,24 @@ void LLPumpIO::processChain(LLChainInfo& chain)
PUMP_DEBUG;
}
+bool LLPumpIO::isChainExpired(LLChainInfo& chain)
+{
+ if(!chain.mHasCurlRequest)
+ {
+ return false ;
+ }
+
+ for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter)
+ {
+ if(!(*iter).mPipe->isValid())
+ {
+ return true ;
+ }
+ }
+
+ return false ;
+}
+
bool LLPumpIO::handleChainError(
LLChainInfo& chain,
LLIOPipe::EStatus error)
@@ -1111,6 +1167,9 @@ bool LLPumpIO::handleChainError(
#endif
keep_going = false;
break;
+ case LLIOPipe::STATUS_EXPIRED:
+ keep_going = false;
+ break ;
default:
if(LLIOPipe::isSuccess(error))
{
@@ -1133,7 +1192,7 @@ LLPumpIO::LLChainInfo::LLChainInfo() :
mInit(false),
mLock(0),
mEOS(false),
- mDescriptorsPool(new LLAPRPool(LLThread::tldata().mRootPool))
+ mHasCurlRequest(false)
{
LLMemType m1(LLMemType::MTYPE_IO_PUMP);
mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS);
diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h
index 75c35ae7ab..d2c5d37571 100644
--- a/indra/llmessage/llpumpio.h
+++ b/indra/llmessage/llpumpio.h
@@ -30,12 +30,11 @@
#define LL_LLPUMPIO_H
#include <set>
-#include <boost/shared_ptr.hpp>
#if LL_LINUX // needed for PATH_MAX in APR.
#include <sys/param.h>
#endif
-#include "llaprpool.h"
+#include "apr_pools.h"
#include "llbuffer.h"
#include "llframetimer.h"
#include "lliopipe.h"
@@ -59,8 +58,9 @@ extern const F32 NEVER_CHAIN_EXPIRY_SECS;
* <code>pump()</code> on a thread used for IO and call
* <code>respond()</code> on a thread that is expected to do higher
* level processing. You can call almost any other method from any
- * thread - see notes for each method for details.
- *
+ * thread - see notes for each method for details. In order for the
+ * threading abstraction to work, you need to call <code>prime()</code>
+ * with a valid apr pool.
* A pump instance manages much of the state for the pipe, including
* the list of pipes in the chain, the channel for each element in the
* chain, the buffer, and if any pipe has marked the stream or process
@@ -79,7 +79,7 @@ public:
/**
* @brief Constructor.
*/
- LLPumpIO(void);
+ LLPumpIO(apr_pool_t* pool);
/**
* @brief Destructor.
@@ -87,6 +87,17 @@ public:
~LLPumpIO();
/**
+ * @brief Prepare this pump for usage.
+ *
+ * If you fail to call this method prior to use, the pump will
+ * try to work, but will not come with any thread locking
+ * mechanisms.
+ * @param pool The apr pool to use.
+ * @return Returns true if the pump is primed.
+ */
+ bool prime(apr_pool_t* pool);
+
+ /**
* @brief Typedef for having a chain of pipes.
*/
typedef std::vector<LLIOPipe::ptr_t> chain_t;
@@ -100,9 +111,10 @@ public:
* @param chain The pipes for the chain
* @param timeout The number of seconds in the future to
* expire. Pass in 0.0f to never expire.
+ * @param has_curl_request The chain contains LLURLRequest if true.
* @return Returns true if anything was added to the pump.
*/
- bool addChain(const chain_t& chain, F32 timeout);
+ bool addChain(const chain_t& chain, F32 timeout, bool has_curl_request = false);
/**
* @brief Struct to associate a pipe with it's buffer io indexes.
@@ -345,19 +357,19 @@ protected:
// basic member data
bool mInit;
+ bool mEOS;
+ bool mHasCurlRequest;
S32 mLock;
LLFrameTimer mTimer;
links_t::iterator mHead;
links_t mChainLinks;
- LLIOPipe::buffer_ptr_t mData;
- bool mEOS;
+ LLIOPipe::buffer_ptr_t mData;
LLSD mContext;
// tracking inside the pump
typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
typedef std::vector<pipe_conditional_t> conditionals_t;
conditionals_t mDescriptors;
- boost::shared_ptr<LLAPRPool> mDescriptorsPool;
};
// All the running chains & info
@@ -376,9 +388,9 @@ protected:
callbacks_t mPendingCallbacks;
callbacks_t mCallbacks;
- // Memory pool for pollsets & mutexes.
- LLAPRPool mPool;
- LLAPRPool mCurrentPool;
+ // memory allocator for pollsets & mutexes.
+ apr_pool_t* mPool;
+ apr_pool_t* mCurrentPool;
S32 mCurrentPoolReallocCount;
#if LL_THREADS_APR
@@ -390,8 +402,9 @@ protected:
#endif
protected:
- void initialize();
-
+ void initialize(apr_pool_t* pool);
+ void cleanup();
+ current_chain_t removeRunningChain(current_chain_t& chain) ;
/**
* @brief Given the internal state of the chains, rebuild the pollset
* @see setConditional()
@@ -418,6 +431,9 @@ protected:
*/
bool handleChainError(LLChainInfo& chain, LLIOPipe::EStatus error);
+ //if the chain is expired, remove it
+ bool isChainExpired(LLChainInfo& chain) ;
+
public:
/**
* @brief Return number of running chains.
diff --git a/indra/llmessage/llsdmessagereader.cpp b/indra/llmessage/llsdmessagereader.cpp
index 304a692cdf..3d8ca2ad9f 100644
--- a/indra/llmessage/llsdmessagereader.cpp
+++ b/indra/llmessage/llsdmessagereader.cpp
@@ -291,9 +291,10 @@ S32 getElementSize(const LLSD& llsd)
case LLSD::TypeMap:
case LLSD::TypeArray:
case LLSD::TypeUndefined:
+ default: // TypeLLSDTypeEnd, TypeLLSDNumTypes, etc.
return 0;
}
- return 0;
+ //return 0;
}
//virtual
diff --git a/indra/llmessage/llsdrpcclient.h b/indra/llmessage/llsdrpcclient.h
index 9fb49a5c33..0cecf4f688 100644
--- a/indra/llmessage/llsdrpcclient.h
+++ b/indra/llmessage/llsdrpcclient.h
@@ -240,9 +240,16 @@ public:
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLSDRPCClientFactory::build" << llendl;
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST));
+ if(!http->isValid())
+ {
+ llwarns << "Creating LLURLRequest failed." << llendl ;
+ delete http;
+ return false;
+ }
+
+ LLIOPipe::ptr_t service(new Client);
+ chain.push_back(service);
LLIOPipe::ptr_t http_pipe(http);
http->addHeader("Content-Type: text/llsd");
if(mURL.empty())
@@ -283,9 +290,16 @@ public:
virtual bool build(LLPumpIO::chain_t& chain, LLSD context) const
{
lldebugs << "LLXMLSDRPCClientFactory::build" << llendl;
- LLIOPipe::ptr_t service(new Client);
- chain.push_back(service);
+
LLURLRequest* http(new LLURLRequest(LLURLRequest::HTTP_POST));
+ if(!http->isValid())
+ {
+ llwarns << "Creating LLURLRequest failed." << llendl ;
+ delete http;
+ return false ;
+ }
+ LLIOPipe::ptr_t service(new Client);
+ chain.push_back(service);
LLIOPipe::ptr_t http_pipe(http);
http->addHeader("Content-Type: text/xml");
if(mURL.empty())
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 91a5a8ce2c..a16f5c7bf0 100644
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -41,7 +41,6 @@
#include "llstring.h"
#include "apr_env.h"
#include "llapr.h"
-#include "llscopedvolatileaprpool.h"
static const U32 HTTP_STATUS_PIPE_ERROR = 499;
/**
@@ -65,7 +64,7 @@ public:
~LLURLRequestDetail();
std::string mURL;
LLCurlEasyRequest* mCurlRequest;
- LLBufferArray* mResponseBuffer;
+ LLIOPipe::buffer_ptr_t mResponseBuffer;
LLChannelDescriptors mChannels;
U8* mLastRead;
U32 mBodyLimit;
@@ -76,7 +75,6 @@ public:
LLURLRequestDetail::LLURLRequestDetail() :
mCurlRequest(NULL),
- mResponseBuffer(NULL),
mLastRead(NULL),
mBodyLimit(0),
mByteAccumulator(0),
@@ -85,13 +83,18 @@ LLURLRequestDetail::LLURLRequestDetail() :
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mCurlRequest = new LLCurlEasyRequest();
+
+ if(!mCurlRequest->isValid()) //failed.
+ {
+ delete mCurlRequest ;
+ mCurlRequest = NULL ;
+ }
}
LLURLRequestDetail::~LLURLRequestDetail()
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
delete mCurlRequest;
- mResponseBuffer = NULL;
mLastRead = NULL;
}
@@ -171,6 +174,7 @@ LLURLRequest::~LLURLRequest()
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
delete mDetail;
+ mDetail = NULL ;
}
void LLURLRequest::setURL(const std::string& url)
@@ -212,31 +216,27 @@ void LLURLRequest::setCallback(LLURLRequestComplete* callback)
// is called with use_proxy = FALSE
void LLURLRequest::useProxy(bool use_proxy)
{
- static std::string env_proxy;
+ static char *env_proxy;
- if (use_proxy && env_proxy.empty())
+ if (use_proxy && (env_proxy == NULL))
{
- char* env_proxy_str;
- LLScopedVolatileAPRPool scoped_pool;
- apr_status_t status = apr_env_get(&env_proxy_str, "ALL_PROXY", scoped_pool);
+ apr_status_t status;
+ LLAPRPool pool;
+ status = apr_env_get(&env_proxy, "ALL_PROXY", pool.getAPRPool());
if (status != APR_SUCCESS)
{
- status = apr_env_get(&env_proxy_str, "http_proxy", scoped_pool);
+ status = apr_env_get(&env_proxy, "http_proxy", pool.getAPRPool());
}
if (status != APR_SUCCESS)
{
- use_proxy = false;
+ use_proxy = FALSE;
}
- else
- {
- // env_proxy_str is stored in the scoped_pool, so we have to make a copy.
- env_proxy = env_proxy_str;
- }
}
- LL_DEBUGS("Proxy") << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (!env_proxy.empty() ? env_proxy : "(null)") << LL_ENDL;
- if (use_proxy && !env_proxy.empty())
+ lldebugs << "use_proxy = " << (use_proxy?'Y':'N') << ", env_proxy = " << (env_proxy ? env_proxy : "(null)") << llendl;
+
+ if (env_proxy && use_proxy)
{
mDetail->mCurlRequest->setoptString(CURLOPT_PROXY, env_proxy);
}
@@ -256,12 +256,24 @@ void LLURLRequest::allowCookies()
mDetail->mCurlRequest->setoptString(CURLOPT_COOKIEFILE, "");
}
+//virtual
+bool LLURLRequest::isValid()
+{
+ return mDetail->mCurlRequest && mDetail->mCurlRequest->isValid();
+}
+
// virtual
LLIOPipe::EStatus LLURLRequest::handleError(
LLIOPipe::EStatus status,
LLPumpIO* pump)
{
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
+
+ if(!isValid())
+ {
+ return STATUS_EXPIRED ;
+ }
+
if(mCompletionCallback && pump)
{
LLURLRequestComplete* complete = NULL;
@@ -330,7 +342,7 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
// *FIX: bit of a hack, but it should work. The configure and
// callback method expect this information to be ready.
- mDetail->mResponseBuffer = buffer.get();
+ mDetail->mResponseBuffer = buffer;
mDetail->mChannels = channels;
if(!configure())
{
@@ -349,7 +361,10 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
static LLFastTimer::DeclareTimer FTM_URL_PERFORM("Perform");
{
LLFastTimer t(FTM_URL_PERFORM);
- mDetail->mCurlRequest->perform();
+ if(!mDetail->mCurlRequest->wait())
+ {
+ return status ;
+ }
}
while(1)
@@ -444,6 +459,12 @@ void LLURLRequest::initialize()
LLMemType m1(LLMemType::MTYPE_IO_URL_REQUEST);
mState = STATE_INITIALIZED;
mDetail = new LLURLRequestDetail;
+
+ if(!isValid())
+ {
+ return ;
+ }
+
mDetail->mCurlRequest->setopt(CURLOPT_NOSIGNAL, 1);
mDetail->mCurlRequest->setWriteCallback(&downCallback, (void*)this);
mDetail->mCurlRequest->setReadCallback(&upCallback, (void*)this);
diff --git a/indra/llmessage/llurlrequest.h b/indra/llmessage/llurlrequest.h
index ec5c2c1941..44d358d906 100644
--- a/indra/llmessage/llurlrequest.h
+++ b/indra/llmessage/llurlrequest.h
@@ -188,6 +188,8 @@ public:
*/
void allowCookies();
+ /*virtual*/ bool isValid() ;
+
public:
/**
* @brief Give this pipe a chance to handle a generated error
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index 7d21e35f96..d0b0e178b8 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -97,10 +97,8 @@ std::string get_shared_secret();
class LLMessagePollInfo
{
public:
- LLMessagePollInfo(void) : mPool(LLThread::tldata().mRootPool) { }
apr_socket_t *mAPRSocketp;
apr_pollfd_t mPollFD;
- LLAPRPool mPool;
};
namespace
@@ -289,13 +287,20 @@ LLMessageSystem::LLMessageSystem(const std::string& filename, U32 port,
}
// LL_DEBUGS("Messaging") << << "*** port: " << mPort << llendl;
- mPollInfop = new LLMessagePollInfo;
-
+ //
+ // Create the data structure that we can poll on
+ //
+ if (!gAPRPoolp)
+ {
+ LL_ERRS("Messaging") << "No APR pool before message system initialization!" << llendl;
+ ll_init_apr();
+ }
apr_socket_t *aprSocketp = NULL;
- apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, mPollInfop->mPool());
+ apr_os_sock_put(&aprSocketp, (apr_os_sock_t*)&mSocket, gAPRPoolp);
+ mPollInfop = new LLMessagePollInfo;
mPollInfop->mAPRSocketp = aprSocketp;
- mPollInfop->mPollFD.p = mPollInfop->mPool();
+ mPollInfop->mPollFD.p = gAPRPoolp;
mPollInfop->mPollFD.desc_type = APR_POLL_SOCKET;
mPollInfop->mPollFD.reqevents = APR_POLLIN;
mPollInfop->mPollFD.rtnevents = 0;
diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h
index 23e1c791f4..2aff90ca1e 100644
--- a/indra/llmessage/tests/networkio.h
+++ b/indra/llmessage/tests/networkio.h
@@ -30,6 +30,7 @@
#define LL_NETWORKIO_H
#include "llmemory.h" // LLSingleton
+#include "llapr.h"
#include "llares.h"
#include "llpumpio.h"
#include "llhttpclient.h"
@@ -47,8 +48,14 @@ public:
mServicePump(NULL),
mDone(false)
{
+ ll_init_apr();
+ if (! gAPRPoolp)
+ {
+ throw std::runtime_error("Can't initialize APR");
+ }
+
// Create IO Pump to use for HTTP Requests.
- mServicePump = new LLPumpIO;
+ mServicePump = new LLPumpIO(gAPRPoolp);
LLHTTPClient::setPump(*mServicePump);
if (ll_init_ares() == NULL || !gAres->isInitialized())
{