Added a thread-safe and robust wrapper for APR pools.

See http://redmine.imprudenceviewer.org/issues/590
and https://jira.secondlife.com/browse/SNOW-596
This commit is contained in:
Aleric Inglewood
2011-05-05 01:34:00 +02:00
parent 5b08560047
commit 4d932d5e2d
57 changed files with 895 additions and 751 deletions

View File

@@ -41,6 +41,7 @@
#include "llhost.h"
#include "llmemtype.h"
#include "llpumpio.h"
#include "llthread.h"
//
// constants
@@ -104,51 +105,31 @@ void ll_debug_socket(const char* msg, apr_socket_t* apr_sock)
///
// static
LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
LLSocket::ptr_t LLSocket::create(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;
// 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;
}
LLSocket::ptr_t rv(new LLSocket);
if(STREAM_TCP == type)
{
status = apr_socket_create(
&socket,
APR_INET,
SOCK_STREAM,
APR_PROTO_TCP,
new_pool);
status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_STREAM, APR_PROTO_TCP, rv->mPool());
}
else if(DATAGRAM_UDP == type)
{
status = apr_socket_create(
&socket,
APR_INET,
SOCK_DGRAM,
APR_PROTO_UDP,
new_pool);
status = apr_socket_create(&rv->mSocket, APR_INET, SOCK_DGRAM, APR_PROTO_UDP, rv->mPool());
}
else
{
if(new_pool) apr_pool_destroy(new_pool);
rv.reset();
return rv;
}
if(ll_apr_warn_status(status))
{
if(new_pool) apr_pool_destroy(new_pool);
rv->mSocket = NULL;
rv.reset();
return rv;
}
rv = ptr_t(new LLSocket(socket, new_pool));
if(port > 0)
{
apr_sockaddr_t* sa = NULL;
@@ -158,7 +139,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
APR_UNSPEC,
port,
0,
new_pool);
rv->mPool());
if(ll_apr_warn_status(status))
{
rv.reset();
@@ -166,8 +147,8 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, 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(socket, APR_SO_REUSEADDR, 1));
status = apr_socket_bind(socket, sa);
ll_apr_warn_status(apr_socket_opt_set(rv->mSocket, APR_SO_REUSEADDR, 1));
status = apr_socket_bind(rv->mSocket, sa);
if(ll_apr_warn_status(status))
{
rv.reset();
@@ -181,7 +162,7 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
// to keep a queue of incoming connections for ACCEPT.
lldebugs << "Setting listen state for socket." << llendl;
status = apr_socket_listen(
socket,
rv->mSocket,
LL_DEFAULT_LISTEN_BACKLOG);
if(ll_apr_warn_status(status))
{
@@ -202,21 +183,28 @@ LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
}
// static
LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
LLSocket::ptr_t LLSocket::create(apr_status_t& status, LLSocket::ptr_t& listen_socket)
{
LLMemType m1(LLMemType::MTYPE_IO_TCP);
LLSocket::ptr_t rv;
if(!socket)
if (!listen_socket->getSocket())
{
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->setOptions();
return rv;
}
bool LLSocket::blockingConnect(const LLHost& host)
{
if(!mSocket) return false;
@@ -229,7 +217,7 @@ bool LLSocket::blockingConnect(const LLHost& host)
APR_UNSPEC,
host.getPort(),
0,
mPool)))
mPool())))
{
return false;
}
@@ -240,13 +228,11 @@ bool LLSocket::blockingConnect(const LLHost& host)
return true;
}
LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool) :
mSocket(socket),
mPool(pool),
LLSocket::LLSocket() :
mSocket(NULL),
mPool(LLThread::tldata().mRootPool),
mPort(PORT_INVALID)
{
ll_debug_socket("Constructing wholely formed socket", mSocket);
LLMemType m1(LLMemType::MTYPE_IO_TCP);
}
LLSocket::~LLSocket()
@@ -258,10 +244,6 @@ LLSocket::~LLSocket()
ll_debug_socket("Destroying socket", mSocket);
apr_socket_close(mSocket);
}
if(mPool)
{
apr_pool_destroy(mPool);
}
}
void LLSocket::setOptions()
@@ -522,10 +504,8 @@ 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),
@@ -585,21 +565,15 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
lldebugs << "accepting socket" << llendl;
PUMP_DEBUG;
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));
apr_status_t status;
LLSocket::ptr_t llsocket(LLSocket::create(status, mListenSocket));
//EStatus rv = STATUS_ERROR;
if(llsocket)
if(llsocket && status == APR_SUCCESS)
{
PUMP_DEBUG;
apr_sockaddr_t* remote_addr;
apr_socket_addr_get(&remote_addr, APR_REMOTE, socket);
apr_socket_addr_get(&remote_addr, APR_REMOTE, llsocket->getSocket());
char* remote_host_string;
apr_sockaddr_ip_get(&remote_host_string, remote_addr);
@@ -614,7 +588,6 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
{
chain.push_back(LLIOPipe::ptr_t(new LLIOSocketWriter(llsocket)));
pump->addChain(chain, mResponseTimeout);
status = STATUS_OK;
}
else
{
@@ -623,7 +596,8 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
}
else
{
llwarns << "Unable to create linden socket." << llendl;
char buf[256];
llwarns << "Unable to accept linden socket: " << apr_strerror(status, buf, sizeof(buf)) << llendl;
}
PUMP_DEBUG;
@@ -636,11 +610,10 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl(
#if 0
LLIODataSocket::LLIODataSocket(
U16 suggested_port,
U16 start_discovery_port,
apr_pool_t* pool) :
U16 start_discovery_port) :
mSocket(NULL)
{
if(!pool || (PORT_INVALID == suggested_port)) return;
if(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;