summaryrefslogtreecommitdiff
path: root/indra/llmessage
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage')
-rw-r--r--indra/llmessage/llassetstorage.h4
-rw-r--r--indra/llmessage/llavatarnamecache.cpp11
-rw-r--r--indra/llmessage/llcoproceduremanager.cpp14
-rw-r--r--indra/llmessage/llcoproceduremanager.h6
-rw-r--r--indra/llmessage/llcorehttputil.cpp2
-rw-r--r--indra/llmessage/llexperiencecache.h3
-rw-r--r--indra/llmessage/llhttpnode.cpp12
-rw-r--r--indra/llmessage/llproxy.h8
-rw-r--r--indra/llmessage/llxfer.cpp2
-rw-r--r--indra/llmessage/llxfer_file.cpp6
-rw-r--r--indra/llmessage/llxfermanager.cpp42
-rw-r--r--indra/llmessage/llxfermanager.h3
-rw-r--r--indra/llmessage/message.cpp9
-rw-r--r--indra/llmessage/message.h7
-rw-r--r--indra/llmessage/tests/commtest.h8
-rw-r--r--indra/llmessage/tests/llhttpclient_test.cpp3
-rw-r--r--indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp3
-rw-r--r--indra/llmessage/tests/lltrustedmessageservice_test.cpp3
-rw-r--r--indra/llmessage/tests/networkio.h8
-rwxr-xr-xindra/llmessage/tests/test_llsdmessage_peer.py33
-rwxr-xr-xindra/llmessage/tests/testrunner.py87
21 files changed, 182 insertions, 92 deletions
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 4be677a4b0..0f23754096 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -181,6 +181,10 @@ protected:
// Map of known bad assets
typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
+// *TODO: these typedefs are passed into the VFS via a legacy C function pointer
+// future project would be to convert these to C++ callables (std::function<>) so that
+// we can use bind and remove the userData parameter.
+//
typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id,
LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status);
diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp
index 1ca5f58ae2..004db546b7 100644
--- a/indra/llmessage/llavatarnamecache.cpp
+++ b/indra/llmessage/llavatarnamecache.cpp
@@ -43,6 +43,8 @@
#include "llcoros.h"
#include "lleventcoro.h"
#include "llcorehttputil.h"
+#include "llexception.h"
+#include "stringize.h"
#include <map>
#include <set>
@@ -231,13 +233,12 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU
LLAvatarNameCache::handleAvNameCacheSuccess(results, httpResults);
}
- catch (std::exception e)
- {
- LL_WARNS() << "Caught exception '" << e.what() << "'" << LL_ENDL;
- }
catch (...)
{
- LL_WARNS() << "Caught unknown exception." << LL_ENDL;
+ LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName()
+ << "('" << url << "', " << agentIds.size()
+ << " Agent Ids)"));
+ throw;
}
}
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index d4c0788b7d..74cdff2b00 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -27,6 +27,8 @@
#include "linden_common.h"
#include "llcoproceduremanager.h"
+#include "llexception.h"
+#include "stringize.h"
#include <boost/assign.hpp>
//=========================================================================
@@ -388,14 +390,14 @@ void LLCoprocedurePool::coprocedureInvokerCoro(LLCoreHttpUtil::HttpCoroutineAdap
{
coproc->mProc(httpAdapter, coproc->mId);
}
- catch (std::exception &e)
- {
- LL_WARNS() << "Coprocedure(" << coproc->mName << ") id=" << coproc->mId.asString() <<
- " threw an exception! Message=\"" << e.what() << "\"" << LL_ENDL;
- }
catch (...)
{
- LL_WARNS() << "A non std::exception was thrown from " << coproc->mName << " with id=" << coproc->mId << "." << " in pool \"" << mPoolName << "\"" << LL_ENDL;
+ LOG_UNHANDLED_EXCEPTION(STRINGIZE("Coprocedure('" << coproc->mName
+ << "', id=" << coproc->mId.asString()
+ << ") in pool '" << mPoolName << "'"));
+ // must NOT omit this or we deplete the pool
+ mActiveCoprocs.erase(itActive);
+ throw;
}
LL_INFOS() << "Finished coprocedure(" << coproc->mName << ")" << " in pool \"" << mPoolName << "\"" << LL_ENDL;
diff --git a/indra/llmessage/llcoproceduremanager.h b/indra/llmessage/llcoproceduremanager.h
index 497367b80c..7d0e83180c 100644
--- a/indra/llmessage/llcoproceduremanager.h
+++ b/indra/llmessage/llcoproceduremanager.h
@@ -37,7 +37,8 @@ class LLCoprocedurePool;
class LLCoprocedureManager : public LLSingleton < LLCoprocedureManager >
{
- friend class LLSingleton < LLCoprocedureManager > ;
+ LLSINGLETON(LLCoprocedureManager);
+ virtual ~LLCoprocedureManager();
public:
typedef boost::function<U32(const std::string &)> SettingQuery_t;
@@ -45,9 +46,6 @@ public:
typedef boost::function<void(LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &, const LLUUID &id)> CoProcedure_t;
- LLCoprocedureManager();
- virtual ~LLCoprocedureManager();
-
/// Places the coprocedure on the queue for processing.
///
/// @param name Is used for debugging and should identify this coroutine.
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index 7742cbc182..9bf38fb336 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -642,7 +642,7 @@ HttpRequestPumper::HttpRequestPumper(const LLCore::HttpRequest::ptr_t &request)
mHttpRequest(request)
{
mBoundListener = LLEventPumps::instance().obtain("mainloop").
- listen(LLEventPump::inventName(), boost::bind(&HttpRequestPumper::pollRequest, this, _1));
+ listen(LLEventPump::ANONYMOUS, boost::bind(&HttpRequestPumper::pollRequest, this, _1));
}
HttpRequestPumper::~HttpRequestPumper()
diff --git a/indra/llmessage/llexperiencecache.h b/indra/llmessage/llexperiencecache.h
index 1002b33f80..8ee7080d38 100644
--- a/indra/llmessage/llexperiencecache.h
+++ b/indra/llmessage/llexperiencecache.h
@@ -43,7 +43,7 @@ class LLUUID;
class LLExperienceCache: public LLSingleton < LLExperienceCache >
{
- friend class LLSingleton < LLExperienceCache > ;
+ LLSINGLETON(LLExperienceCache);
public:
typedef boost::function<std::string(const std::string &)> CapabilityQuery_t;
@@ -103,7 +103,6 @@ public:
static const int PROPERTY_SUSPENDED; // 1 << 7
private:
- LLExperienceCache();
virtual ~LLExperienceCache();
virtual void initSingleton();
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index f235965879..04b34a296c 100644
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -31,6 +31,7 @@
#include "llstl.h"
#include "llhttpconstants.h"
+#include "llexception.h"
const std::string CONTEXT_HEADERS("headers");
const std::string CONTEXT_PATH("path");
@@ -92,27 +93,28 @@ LLHTTPNode::~LLHTTPNode()
namespace {
- class NotImplemented
+ struct NotImplemented: public LLException
{
+ NotImplemented(): LLException("LLHTTPNode::NotImplemented") {}
};
}
// virtual
LLSD LLHTTPNode::simpleGet() const
{
- throw NotImplemented();
+ LLTHROW(NotImplemented());
}
// virtual
LLSD LLHTTPNode::simplePut(const LLSD& input) const
{
- throw NotImplemented();
+ LLTHROW(NotImplemented());
}
// virtual
LLSD LLHTTPNode::simplePost(const LLSD& input) const
{
- throw NotImplemented();
+ LLTHROW(NotImplemented());
}
@@ -172,7 +174,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons
// virtual
LLSD LLHTTPNode::simpleDel(const LLSD&) const
{
- throw NotImplemented();
+ LLTHROW(NotImplemented());
}
// virtual
diff --git a/indra/llmessage/llproxy.h b/indra/llmessage/llproxy.h
index bd23dd39de..688dff7c83 100644
--- a/indra/llmessage/llproxy.h
+++ b/indra/llmessage/llproxy.h
@@ -218,14 +218,14 @@ enum LLSocks5AuthType
*/
class LLProxy: public LLSingleton<LLProxy>
{
- LOG_CLASS(LLProxy);
-public:
/*###########################################################################################
METHODS THAT DO NOT LOCK mProxyMutex!
###########################################################################################*/
// Constructor, cannot have parameters due to LLSingleton parent class. Call from main thread only.
- LLProxy();
+ LLSINGLETON(LLProxy);
+ LOG_CLASS(LLProxy);
+public:
// Static check for enabled status for UDP packets. Call from main thread only.
static bool isSOCKSProxyEnabled() { return sUDPProxyEnabled; }
@@ -239,9 +239,11 @@ public:
/*###########################################################################################
METHODS THAT LOCK mProxyMutex! DO NOT CALL WHILE mProxyMutex IS LOCKED!
###########################################################################################*/
+private:
// Destructor, closes open connections. Do not call directly, use cleanupClass().
~LLProxy();
+public:
// Delete LLProxy singleton. Allows the apr_socket used in the SOCKS 5 control channel to be
// destroyed before the call to apr_terminate. Call from main thread only.
static void cleanupClass();
diff --git a/indra/llmessage/llxfer.cpp b/indra/llmessage/llxfer.cpp
index 4aba5cae72..e0590dfdff 100644
--- a/indra/llmessage/llxfer.cpp
+++ b/indra/llmessage/llxfer.cpp
@@ -294,7 +294,7 @@ S32 LLXfer::processEOF()
}
else
{
- LL_INFOS() << "xfer from " << mRemoteHost << " failed, code "
+ LL_INFOS() << "xfer from " << mRemoteHost << " failed or aborted, code "
<< mCallbackResult << ": " << getFileName() << LL_ENDL;
}
diff --git a/indra/llmessage/llxfer_file.cpp b/indra/llmessage/llxfer_file.cpp
index 257a13f277..8e2ed890e7 100644
--- a/indra/llmessage/llxfer_file.cpp
+++ b/indra/llmessage/llxfer_file.cpp
@@ -98,12 +98,12 @@ void LLXfer_File::cleanup ()
mFp = NULL;
}
- LLFile::remove(mTempFilename);
+ LLFile::remove(mTempFilename, ENOENT);
if (mDeleteLocalOnCompletion)
{
LL_DEBUGS() << "Removing file: " << mLocalFilename << LL_ENDL;
- LLFile::remove(mLocalFilename);
+ LLFile::remove(mLocalFilename, ENOENT);
}
else
{
@@ -321,7 +321,7 @@ S32 LLXfer_File::processEOF()
mCallbackResult = flushval;
}
- LLFile::remove(mLocalFilename);
+ LLFile::remove(mLocalFilename, ENOENT);
if (!mCallbackResult)
{
diff --git a/indra/llmessage/llxfermanager.cpp b/indra/llmessage/llxfermanager.cpp
index 0ab67b8dda..2ceb64ce8f 100644
--- a/indra/llmessage/llxfermanager.cpp
+++ b/indra/llmessage/llxfermanager.cpp
@@ -401,7 +401,7 @@ U64 LLXferManager::registerXfer(const void *datap, const S32 length)
///////////////////////////////////////////////////////////
-void LLXferManager::requestFile(const std::string& local_filename,
+U64 LLXferManager::requestFile(const std::string& local_filename,
const std::string& remote_filename,
ELLPath remote_path,
const LLHost& remote_host,
@@ -424,10 +424,12 @@ void LLXferManager::requestFile(const std::string& local_filename,
{
// cout << "requested a xfer already in progress" << endl;
- return;
+ return xferp->mID;
}
}
+ U64 xfer_id = 0;
+
S32 chunk_size = use_big_packets ? LL_XFER_LARGE_PAYLOAD : -1;
xferp = (LLXfer *) new LLXfer_File(chunk_size);
if (xferp)
@@ -438,13 +440,15 @@ void LLXferManager::requestFile(const std::string& local_filename,
// around.
// Note: according to AaronB, this is here to deal with locks on files that were
// in transit during a crash,
- if(delete_remote_on_completion &&
- (remote_filename.substr(remote_filename.length()-4) == ".tmp"))
+ if( delete_remote_on_completion
+ && (remote_filename.substr(remote_filename.length()-4) == ".tmp")
+ && gDirUtilp->fileExists(local_filename))
{
- LLFile::remove(local_filename);
+ LLFile::remove(local_filename, ENOENT);
}
+ xfer_id = getNextID();
((LLXfer_File *)xferp)->initializeRequest(
- getNextID(),
+ xfer_id,
local_filename,
remote_filename,
remote_path,
@@ -457,6 +461,7 @@ void LLXferManager::requestFile(const std::string& local_filename,
{
LL_ERRS() << "Xfer allocation error" << LL_ENDL;
}
+ return xfer_id;
}
void LLXferManager::requestFile(const std::string& remote_filename,
@@ -616,7 +621,7 @@ void LLXferManager::processReceiveData (LLMessageSystem *mesgsys, void ** /*user
if (!xferp)
{
char U64_BUF[MAX_STRING]; /* Flawfinder : ignore */
- LL_WARNS() << "received xfer data from " << mesgsys->getSender()
+ LL_INFOS() << "received xfer data from " << mesgsys->getSender()
<< " for non-existent xfer id: "
<< U64_to_str(id, U64_BUF, sizeof(U64_BUF)) << LL_ENDL;
return;
@@ -1103,6 +1108,29 @@ void LLXferManager::retransmitUnackedPackets ()
}
}
+///////////////////////////////////////////////////////////
+
+void LLXferManager::abortRequestById(U64 xfer_id, S32 result_code)
+{
+ LLXfer * xferp = findXfer(xfer_id, mReceiveList);
+ if (xferp)
+ {
+ if (xferp->mStatus == e_LL_XFER_IN_PROGRESS)
+ {
+ // causes processAbort();
+ xferp->abort(result_code);
+ }
+ else
+ {
+ xferp->mCallbackResult = result_code;
+ xferp->processEOF(); //should notify requester
+ removeXfer(xferp, &mReceiveList);
+ }
+ // Since already removed or marked as aborted no need
+ // to wait for processAbort() to start new download
+ startPendingDownloads();
+ }
+}
///////////////////////////////////////////////////////////
diff --git a/indra/llmessage/llxfermanager.h b/indra/llmessage/llxfermanager.h
index b3d110e7a1..d258f0a5ce 100644
--- a/indra/llmessage/llxfermanager.h
+++ b/indra/llmessage/llxfermanager.h
@@ -140,7 +140,7 @@ class LLXferManager
// file requesting routines
// .. to file
- virtual void requestFile(const std::string& local_filename,
+ virtual U64 requestFile(const std::string& local_filename,
const std::string& remote_filename,
ELLPath remote_path,
const LLHost& remote_host,
@@ -202,6 +202,7 @@ class LLXferManager
virtual void retransmitUnackedPackets ();
// error handling
+ void abortRequestById(U64 xfer_id, S32 result_code);
virtual void processAbort (LLMessageSystem *mesgsys, void **user_data);
};
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index cecb2021e7..6ef4025ab1 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -76,6 +76,7 @@
#include "v4math.h"
#include "lltransfertargetvfile.h"
#include "llcorehttputil.h"
+#include "llpounceable.h"
// Constants
//const char* MESSAGE_LOG_FILENAME = "message.log";
@@ -1724,7 +1725,9 @@ std::ostream& operator<<(std::ostream& s, LLMessageSystem &msg)
return s;
}
-LLMessageSystem *gMessageSystem = NULL;
+// LLPounceable supports callWhenReady(), to permit clients to queue up (e.g.)
+// callback registrations for when gMessageSystem is first assigned
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
// update appropriate ping info
void process_complete_ping_check(LLMessageSystem *msgsystem, void** /*user_data*/)
@@ -2641,7 +2644,7 @@ void end_messaging_system(bool print_summary)
LL_INFOS("Messaging") << str.str().c_str() << LL_ENDL;
}
- delete gMessageSystem;
+ delete static_cast<LLMessageSystem*>(gMessageSystem);
gMessageSystem = NULL;
}
}
@@ -4007,7 +4010,7 @@ void LLMessageSystem::sendUntrustedSimulatorMessageCoro(std::string url, std::st
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("groupMembersRequest", httpPolicy));
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("untrustedSimulatorMessage", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index 133db620e6..f6c5d9e228 100644
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -60,6 +60,7 @@
#include "llstoredmessage.h"
#include "boost/function.hpp"
+#include "llpounceable.h"
const U32 MESSAGE_MAX_STRINGS_LENGTH = 64;
const U32 MESSAGE_NUMBER_OF_HASH_BUCKETS = 8192;
@@ -68,10 +69,10 @@ const S32 MESSAGE_MAX_PER_FRAME = 400;
class LLMessageStringTable : public LLSingleton<LLMessageStringTable>
{
-public:
- LLMessageStringTable();
+ LLSINGLETON(LLMessageStringTable);
~LLMessageStringTable();
+public:
char *getString(const char *str);
U32 mUsed;
@@ -832,7 +833,7 @@ private:
// external hook into messaging system
-extern LLMessageSystem *gMessageSystem;
+extern LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
// Must specific overall system version, which is used to determine
// if a patch is available in the message template checksum verification.
diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h
index 0d149b5258..7c8f27bbd2 100644
--- a/indra/llmessage/tests/commtest.h
+++ b/indra/llmessage/tests/commtest.h
@@ -33,15 +33,15 @@
#include "llevents.h"
#include "llsd.h"
#include "llhost.h"
+#include "llexception.h"
#include "stringize.h"
#include <map>
#include <string>
-#include <stdexcept>
#include <boost/lexical_cast.hpp>
-struct CommtestError: public std::runtime_error
+struct CommtestError: public LLException
{
- CommtestError(const std::string& what): std::runtime_error(what) {}
+ CommtestError(const std::string& what): LLException(what) {}
};
static bool query_verbose()
@@ -68,7 +68,7 @@ static int query_port(const std::string& var)
const char* cport = getenv(var.c_str());
if (! cport)
{
- throw CommtestError(STRINGIZE("missing environment variable" << var));
+ LLTHROW(CommtestError(STRINGIZE("missing environment variable" << var)));
}
// This will throw, too, if the value of PORT isn't numeric.
int port(boost::lexical_cast<int>(cport));
diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp
index a32bfa59ce..9356a14f1f 100644
--- a/indra/llmessage/tests/llhttpclient_test.cpp
+++ b/indra/llmessage/tests/llhttpclient_test.cpp
@@ -42,6 +42,7 @@
#include "lliosocket.h"
#include "stringize.h"
+#include "llcleanup.h"
namespace tut
{
@@ -66,7 +67,7 @@ namespace tut
~HTTPClientTestData()
{
delete mClientPump;
- LLProxy::cleanupClass();
+ SUBSYSTEM_CLEANUP(LLProxy);
apr_pool_destroy(mPool);
}
diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp
index 3b04530c1a..e20f61b73f 100644
--- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp
+++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp
@@ -31,11 +31,12 @@
#include "llhost.h"
#include "message.h"
#include "llsd.h"
+#include "llpounceable.h"
#include "llhost.cpp" // Needed for copy operator
#include "net.cpp" // Needed by LLHost.
-LLMessageSystem * gMessageSystem = NULL;
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
// sensor test doubles
bool gClearRecvWasCalled = false;
diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp
index 55748ad27e..41f982a7e2 100644
--- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp
+++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp
@@ -33,8 +33,9 @@
#include "message.h"
#include "llmessageconfig.h"
#include "llhttpnode_stub.cpp"
+#include "llpounceable.h"
-LLMessageSystem* gMessageSystem = NULL;
+LLPounceable<LLMessageSystem*, LLPounceableStatic> gMessageSystem;
LLMessageConfig::SenderTrust
LLMessageConfig::getSenderTrustedness(const std::string& msg_name)
diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h
index 2aff90ca1e..5986524342 100644
--- a/indra/llmessage/tests/networkio.h
+++ b/indra/llmessage/tests/networkio.h
@@ -34,6 +34,7 @@
#include "llares.h"
#include "llpumpio.h"
#include "llhttpclient.h"
+#include "llexception.h"
/*****************************************************************************
* NetworkIO
@@ -43,7 +44,7 @@
// init time. Use the lazy, on-demand initialization we get from LLSingleton.
class NetworkIO: public LLSingleton<NetworkIO>
{
-public:
+ LLSINGLETON(NetworkIO);
NetworkIO():
mServicePump(NULL),
mDone(false)
@@ -51,7 +52,7 @@ public:
ll_init_apr();
if (! gAPRPoolp)
{
- throw std::runtime_error("Can't initialize APR");
+ LLTHROW(LLException("Can't initialize APR"));
}
// Create IO Pump to use for HTTP Requests.
@@ -59,7 +60,7 @@ public:
LLHTTPClient::setPump(*mServicePump);
if (ll_init_ares() == NULL || !gAres->isInitialized())
{
- throw std::runtime_error("Can't start DNS resolver");
+ LLTHROW(LLException("Can't start DNS resolver"));
}
// You can interrupt pump() without waiting the full timeout duration
@@ -68,6 +69,7 @@ public:
boost::bind(&NetworkIO::done, this, _1));
}
+public:
bool pump(F32 timeout=10)
{
// Reset the done flag so we don't pop out prematurely
diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py
index e45249b1cb..9cd2959ea1 100755
--- a/indra/llmessage/tests/test_llsdmessage_peer.py
+++ b/indra/llmessage/tests/test_llsdmessage_peer.py
@@ -31,13 +31,10 @@ $/LicenseInfo$
import os
import sys
-from threading import Thread
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
-mydir = os.path.dirname(__file__) # expected to be .../indra/llmessage/tests/
-sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
-from indra.util.fastest_elementtree import parse as xml_parse
-from indra.base import llsd
+from llbase.fastest_elementtree import parse as xml_parse
+from llbase import llsd
from testrunner import freeport, run, debug, VERBOSE
import time
@@ -157,17 +154,23 @@ class Server(HTTPServer):
allow_reuse_address = False
if __name__ == "__main__":
- # Instantiate a Server(TestHTTPRequestHandler) on the first free port
- # in the specified port range. Doing this inline is better than in a
- # daemon thread: if it blows up here, we'll get a traceback. If it blew up
- # in some other thread, the traceback would get eaten and we'd run the
- # subject test program anyway.
- httpd, port = freeport(xrange(8000, 8020),
- lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler))
+ # function to make a server with specified port
+ make_server = lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler)
+
+ if not sys.platform.startswith("win"):
+ # Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the
+ # runtime.
+ httpd = make_server(0)
+ else:
+ # "Then there's Windows"
+ # Instantiate a Server(TestHTTPRequestHandler) on the first free port
+ # in the specified port range.
+ httpd, port = freeport(xrange(8000, 8020), make_server)
+
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
# command-line parsing -- and anyway, for C++ integration tests, that's
# performed in TUT code rather than our own.
- os.environ["PORT"] = str(port)
- debug("$PORT = %s", port)
- sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:]))
+ os.environ["PORT"] = str(httpd.server_port)
+ debug("$PORT = %s", httpd.server_port)
+ sys.exit(run(server_inst=httpd, *sys.argv[1:]))
diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py
index 5b9beb359b..c25945067e 100755
--- a/indra/llmessage/tests/testrunner.py
+++ b/indra/llmessage/tests/testrunner.py
@@ -27,13 +27,12 @@ Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
$/LicenseInfo$
"""
-from __future__ import with_statement
-
import os
import sys
import re
import errno
import socket
+import subprocess
VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "0") # default to quiet
# Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if
@@ -47,6 +46,9 @@ if VERBOSE:
else:
debug = lambda *args: None
+class Error(Exception):
+ pass
+
def freeport(portlist, expr):
"""
Find a free server port to use. Specifically, evaluate 'expr' (a
@@ -141,34 +143,73 @@ def freeport(portlist, expr):
raise
def run(*args, **kwds):
- """All positional arguments collectively form a command line, executed as
- a synchronous child process.
- In addition, pass server=new_thread_instance as an explicit keyword (to
- differentiate it from an additional command-line argument).
- new_thread_instance should be an instantiated but not yet started Thread
- subclass instance, e.g.:
- run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd"))
"""
- # If there's no server= keyword arg, don't start a server thread: simply
- # run a child process.
+ Run a specified command as a synchronous child process, optionally
+ launching a server Thread during the run.
+
+ All positional arguments collectively form a command line. The first
+ positional argument names the program file to execute.
+
+ Returns the termination code of the child process.
+
+ In addition, you may pass keyword-only arguments:
+
+ use_path=True: allow a simple filename as command and search PATH for that
+ filename. (This argument is retained for backwards compatibility but is
+ now the default behavior.)
+
+ server_inst: an instance of a subclass of SocketServer.BaseServer.
+
+ When you pass server_inst, run() calls its handle_request() method in a
+ loop until the child process terminates.
+ """
+ # server= keyword arg is discontinued
try:
thread = kwds.pop("server")
except KeyError:
pass
else:
- # Start server thread. Note that this and all other comm server
- # threads should be daemon threads: we'll let them run "forever,"
- # confident that the whole process will terminate when the main thread
- # terminates, which will be when the child process terminates.
- thread.setDaemon(True)
- thread.start()
- # choice of os.spawnv():
- # - [v vs. l] pass a list of args vs. individual arguments,
- # - [no p] don't use the PATH because we specifically want to invoke the
- # executable passed as our first arg,
- # - [no e] child should inherit this process's environment.
+ raise Error("Obsolete call to testrunner.run(): pass server_inst=, not server=")
+
debug("Running %s...", " ".join(args))
- rc = os.spawnv(os.P_WAIT, args[0], args)
+
+ try:
+ server_inst = kwds.pop("server_inst")
+ except KeyError:
+ # Without server_inst, this is very simple: just run child process.
+ rc = subprocess.call(args)
+ else:
+ # We're being asked to run a local server while the child process
+ # runs. We used to launch a daemon thread calling
+ # server_inst.serve_forever(), then eventually call sys.exit() with
+ # the daemon thread still running -- but in recent versions of Python
+ # 2, even when you call sys.exit(0), apparently killing the thread
+ # causes the Python runtime to force the process termination code
+ # nonzero. So now we avoid the extra thread altogether.
+
+ # SocketServer.BaseServer.handle_request() honors a 'timeout'
+ # attribute, if it's set to something other than None.
+ # We pick 0.5 seconds because that's the default poll timeout for
+ # BaseServer.serve_forever(), which is what we used to use.
+ server_inst.timeout = 0.5
+
+ child = subprocess.Popen(args)
+ while child.poll() is None:
+ # Setting server_inst.timeout is what keeps this handle_request()
+ # call from blocking "forever." Interestingly, looping over
+ # handle_request() with a timeout is very like the implementation
+ # of serve_forever(). We just check a different flag to break out.
+ # It might be interesting if handle_request() returned an
+ # indication of whether it in fact handled a request or timed out.
+ # Oddly, it doesn't. We could discover that by overriding
+ # handle_timeout(), whose default implementation does nothing --
+ # but in fact we really don't care. All that matters is that we
+ # regularly poll both the child process and the server socket.
+ server_inst.handle_request()
+ # We don't bother to capture the rc returned by child.poll() because
+ # poll() is already defined to capture that in its returncode attr.
+ rc = child.returncode
+
debug("%s returned %s", args[0], rc)
return rc